PDA

View Full Version : QGraphicsView coordinate system



roband915
16th February 2011, 15:22
I´ve been reading about QGraphicsView/Scene/Item all day and still I fail to understand how it works. I started with QT Creator and added a QGraphicsView to the mainWindow. Then I subclassed QGraphicsScene and QGraphicsItem(I probably need to subclass the QGraphicsView later on). I use shapelib to open a shape-file and If I´ve done it right it will be implemented as a QGraphicsItem. I add the item to the scene and the scene to the view. I can see the map(shapefile) but it´s centered and very small. So I thought let´s change the coordinatesystem of the scene... And this is where I got stuck.
I know the boundaries of the GraphicsView and the Scene. I also know the boundaries of the shapefile. Why can´t I tell the scene to have the same boundaries as the shapefile but extend it to the size of the view!?
Maybe it isn´t hard but obviously I don´t have the brains for it so any help at all will be very appreciated.

Code for subclassed QGraphicsItem



item::item(QGraphicsItem *parent)
: QGraphicsItem(parent)
{
}

QRectF item::boundingRect() const
{
QRectF recWindow;
recWindow.setBottomLeft(QPointF(sBoundingBox.minX, sBoundingBox.minY));
recWindow.setBottomRight(QPointF(sBoundingBox.maxX , sBoundingBox.minY));
recWindow.setTopLeft(QPointF(sBoundingBox.minX,sBo undingBox.maxY));
recWindow.setTopRight(QPointF(sBoundingBox.maxX,sB oundingBox.maxY));
return recWindow;
}

void item::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
OpenShapeFile("./Maps/Norden_wgs84.shp");
painter->setRenderHint(QPainter::Antialiasing);
painter->setBrush(Qt::blue);

for(int i = 0;i< vMap.size(); i++)
{
painter->drawPolyline(vMap.at(i)->p.data() ,vMap.at(i)->p.size());
}
}

I´m not really doing anything in the subclassed QGraphicsScene yet so I don´t think there is any reason to show the code.

And here is the mainWindow


IceChart3::IceChart3(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);

QRect sceneRect;
sceneRect.setBottomLeft(QPoint(4,52));
sceneRect.setBottomRight(QPoint(42, 52));
sceneRect.setTopLeft(QPoint(4,72));
sceneRect.setTopRight(QPoint(42,72));

scene = new MyScene(this);
scene->setSceneRect(sceneRect);

itemMap = new item();

scene->addItem(itemMap);

//Flip upside down.
ui.graphicsView->scale(1,-1);

//Set scene to view
ui.graphicsView->setScene(scene);

totem
16th February 2011, 18:16
To zoom on a rect I use QGraphicsView::fitInView()

roband915
16th February 2011, 19:46
Hmm I tried it like this and it does nothing I'm afraid. Probably I'm not doing it right?



MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);

QRectF recWindow;
recWindow.setBottomLeft(QPointF(4.,52.));
recWindow.setBottomRight(QPointF(42., 52.));
recWindow.setTopLeft(QPointF(4.,72.));
recWindow.setTopRight(QPointF(42.,72.));

scene = new MyScene(this);
test = new item();

scene->setSceneRect(recWindow);
ui->graphicsView->fitInView(recWindow,Qt::IgnoreAspectRatio);

scene->addItem(test);
ui->graphicsView->setScene(scene);

totem
16th February 2011, 21:16
I did not try really but this should do the trick.
by the way the rect you define does not seem valid, unless you invert top and bottom (like you scaled view's Y in first post)



MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);

scene = new MyScene(this);
ui->graphicsView->setScene(scene);

test = new item();
scene->addItem(test);

ui->graphicsView->fitInView(scene->itemsBoundingRect());
}

roband915
17th February 2011, 08:26
That didn´t work either I´m afraid. I´ve managed to implement a zoom-function. And for a moment I saw a light in the tunnel actually...But this function only works halfway so to speak. After just a few rolls with the scrollwheel on the mouse everything turns white.



void IceChart3::wheelEvent(QWheelEvent *event)
{
//Get the position of the mouse before scaling, in scene coords
QPointF pointBeforeScale(ui.graphicsView->mapToScene(event->pos()));

//Get the original screen centerpoint
QPointF screenCenter = GetCenter(); //CurrentCenterPoint; //(visRect.center());

double scaleFactor = 2.15; //How fast we zoom
if(event->delta() > 0)
{
//Zoom in
ui.graphicsView->scale(scaleFactor, scaleFactor);
}
else
{
//Zooming out
ui.graphicsView->scale(1.0 / scaleFactor, 1.0 / scaleFactor);
}

//Get the position after scaling, in scene coords
QPointF pointAfterScale(ui.graphicsView->mapToScene(event->pos()));

//Get the offset of how the screen moved
QPointF offset = pointBeforeScale - pointAfterScale;

//Adjust to the new center for correct zooming
QPointF newCenter = screenCenter + offset;
SetCenter(newCenter);
}


Thank you totem by the way for taking the time to help me. If I could I´d by you a beer :)

totem
17th February 2011, 09:54
That didn´t work either I´m afraid

What happened then ?

Speaking of zoom method, here is how I usually do :


void MyView::wheelEvent(QWheelEvent *e)
{
const qreal zoomStep = 0.25 ;
double zoomFactor = pow( 2.0, e->delta() / 8.0 / 15.0 * zoomStep ) ;
scale(zoomFactor, zoomFactor);

e->setModifiers(Qt::NoModifier) ; // to avoid [CTRL+wheel] behave like QAbstractScrollArea, maybe not useful for everyone
QGraphicsView::wheelEvent(e) ;
}

Plus, you can choose to zoom on view's center or under cursor using QGraphiscView::transformationAnchor

roband915
17th February 2011, 11:30
Nothing really. The map(QGraphicsItem) is still centered and small.

I tried your zoom method and I still get the same result. After just a few movements with the wheel then the map disappears.

totem
17th February 2011, 12:42
After adding an item to the scene, the following code should have worked


ui->graphicsView->fitInView(scene->itemsBoundingRect());

Can you post your graphicsitem's code ? because I don't see were the problem comes from. Something must be wrong, like item's bounding rect or something

roband915
17th February 2011, 12:54
Hmm ok maybe like you said I´m doing something wrong in with the QGraphicsItem.
Here is the .h file


#ifndef ITEM_H
#define ITEM_H

#include <QGraphicsItem>
#include <QPointF>
#include <QRectF>
#include <QPolygonF>
#include <QPainter>
#include <QPainterPath>
#include <QWidget>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsSceneHoverEvent>
#include <QMessageBox>
#include <shapelib/shapefil.h>

#include <object.h>

class item : public QObject, public QGraphicsItem
{
Q_OBJECT
public:
item(QGraphicsItem *parent = 0);

QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
void OpenShapeFile(char *fileName);

virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
virtual void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent);
virtual void mouseMoveEvent(QGraphicsSceneEvent *event);

QVector<object*> vMap;
object *map;

private:
typedef struct MyPoint2D
{
double x;
double y;
}MyPoint2D;

std::vector<MyPoint2D> vPoints;

typedef struct MyLineString2D
{
std::vector<MyPoint2D> vPointList;
}MyLineString2D;

//Holds coordinates of Line Shapefile
std::vector<MyLineString2D> vLines;

typedef struct MyPolygon2D
{
std::vector<MyPoint2D> vPointList;

}MyPolygon2D;

//Holds coordinates of Polygon Shapefile
std::vector<MyPolygon2D> vPolygons;

typedef struct SBoundingBox
{
qreal maxX;
qreal maxY;
qreal minX;
qreal minY;
}SBoundingBox;

qreal xMax,yMax,x2Min,y2Min;
//BoundingBox of Shapefile
SBoundingBox sBoundingBox;
};

#endif // ITEM_H


And the .cpp file



#include "item.h"

item::item(QGraphicsItem *parent)
: QObject(), QGraphicsItem(parent)
{
setAcceptHoverEvents(true);
setFlags(ItemIsMovable | ItemIsFocusable | QGraphicsItem::ItemIsSelectable);
}

QRectF item::boundingRect() const
{
QRectF recWindow;
recWindow.setBottomLeft(QPointF(sBoundingBox.minX, sBoundingBox.minY));
recWindow.setBottomRight(QPointF(sBoundingBox.maxX , sBoundingBox.minY));
recWindow.setTopLeft(QPointF(sBoundingBox.minX,sBo undingBox.maxY));
recWindow.setTopRight(QPointF(sBoundingBox.maxX,sB oundingBox.maxY));
return recWindow;
}

void item::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
OpenShapeFile("./Maps/Norden_wgs84.shp");
painter->setRenderHint(QPainter::Antialiasing);
painter->setBrush(Qt::red);

for(int i = 0;i< vMap.size(); i++)
{
painter->drawPolyline(vMap.at(i)->p.data() ,vMap.at(i)->p.size());
}
}

void item::hoverEnterEvent(QGraphicsSceneHoverEvent* event)
{
}

void item::mousePressEvent(QGraphicsSceneMouseEvent* event)
{
}

void item::mouseMoveEvent(QGraphicsSceneEvent *event)
{
}

void item::OpenShapeFile(char *fileName)
{
SHPHandle hSHP = SHPOpen(fileName, "rb");

if(hSHP == NULL)
{
QMessageBox m;
m.setText("Could not open shape.");
m.exec();
}
else
{
//Read boundingbox of shapefile.
sBoundingBox.maxX = hSHP->adBoundsMax[0];
sBoundingBox.maxY = hSHP->adBoundsMax[1];

sBoundingBox.minX = hSHP->adBoundsMin[0];
sBoundingBox.minY = hSHP->adBoundsMin[1];

//Point shape-file
if(hSHP->nShapeType == SHPT_POINT)
{
SHPObject *psShape;
for(int i=0;i<hSHP->nRecords;i++)
{
psShape = SHPReadObject(hSHP, i);
double fX = psShape->padfX[0];
double fY = -psShape->padfY[0];

//Plot these points
MyPoint2D pt;
pt.x = fX;
pt.y = fY;

vPoints.push_back(pt);
}
}

//Line Shapefile
else if(hSHP->nShapeType == SHPT_ARC)
{
SHPObject *psShape;

for(int i=0;i<hSHP->nRecords;i++)
{
psShape = SHPReadObject(hSHP, i);
std::vector<MyPoint2D> tempPointArray;
QVector<QPointF> tempQPointArray;
map = new object();

for(int j=0;j<psShape->nVertices;j++)
{
double fX = psShape->padfX[j];
double fY = psShape->padfY[j];
MyPoint2D pt;
pt.x = fX;
pt.y= fY;

//QT Point
QPointF test = QPointF(fX,fY);

map->addVertices(test);
tempPointArray.push_back(pt);
}

vMap.push_back(map);

MyLineString2D linestring;
linestring.vPointList=tempPointArray;
vLines.push_back(linestring);
}
}

//Polygon Shapefile
if(hSHP->nShapeType == SHPT_POLYGON)
{
SHPObject *psShape;
for(int i=0;i<hSHP->nRecords;i++)
{
psShape = SHPReadObject(hSHP, i);
std::vector<MyPoint2D> tempPointArray;

for(int j=0;j<psShape->nVertices;j++)
{
double fX = psShape->padfX[j];
double fY = psShape->padfY[j];
MyPoint2D pt;
pt.x = fX;
pt.y= fY;

tempPointArray.push_back(pt);
}

MyPolygon2D polygon;
polygon.vPointList = tempPointArray;
vPolygons.push_back(polygon);
}
}
}
}

totem
17th February 2011, 14:01
Looking your ::boundingRect() method, did you scale view's Y to -1 or not ?
In QGraphicsScene nominal coordinate system, the bottom of a valid QRectF has a greater value than its top, which is not the case in your code (bottom<top).

Try to define your boundingrect as follow : a point in space (x,y) and 2D dimensions (width,height)

Otherwise I don't see what can be wrong for now..

Beside, you define custom structs where using Qt would just be fine : I'm thinking of

MyPolygon2D => QPolygonF
MyPoint2D => QPointF
MyLineString2D => QPainterPath
SBoundingBox => QRectF

Another thing : you read your file and initialize your structs each time you paint your item, which is not good. You could read your file once in constructor, initialize some member and use these members in your paint method. Plus, it seems your OpenShapeFile() contains memory leaks (1 new == 1 delete somewhere in your code)

wysota
17th February 2011, 22:35
Sorry to butt in like this but if your whole shapefile is represented by a single item then that's probably not a very good approach. As for zooming, what you want is to zoom in the view on the item and not zoom in the view on the scene.

Something like:

ui->graphicsView->setScene(scene);
scene->addItem(test);
ui->graphicsView->fitInView(test->sceneRect(), Qt::KeepAspectRatio);

robertson1
18th February 2011, 00:02
I have had a similar thing happen (screen going white / disapearing) when my custom items bounding rect has been wrong. Try just adding a normal QGraphicsLineIteminstead to see if your zooming is ok.

I had good results displaying dwg files by just with a QGraphicsItemGroup and just adding the individual lines, text, path items.

swapan_gh
18th September 2013, 11:53
can you please send me the source folder

swapan_gh
19th September 2013, 08:51
hi all,

I would try if you share me the total source code folder. other way share object.h file and mainwindow.cpp, mainwindow.h,main.cpp.

Thanks & regards,

Swapan

swapan_gh
29th October 2013, 10:25
if possible then share the source for object.h file

swapan_gh
5th December 2013, 06:58
Atlast I solve the problem.........

swapan