PDA

View Full Version : QGraphicsScene with lots of static items



lari
19th April 2010, 15:25
Hi!

I'd like to write a browser for nucleotide sequence alignments. You could see "alignments" as huge matrices of coloured tiles, with the background colour of the tile and the letter printed on it indicating the type of nucleotide at that position. The matrix is full and, when displayed, the area is completely covered by the tiles. The content of the matrix doesn't change and we only want to display it. The size of the matrix varies a lot: it can be from 20 (rows) x 500 (columns) up to hundreds or thousands of rows and tens or hundreds of thousands of columns. We can here assume that it is 80 rows times 5000 columns, giving in total 400k tiles. "Browsing the alignment" means that we can move around to see different parts of the matrix and zoom in/out to see either exact details or an overview.

I have an implementation that seems to work reasonably well but there are details that could be improved (see blow for the code). I followed the 4k Chips example and used objects inheriting QGraphicsItem to show more details (letter) when zoomed in and only the colour when zoomed out. The main problem in my implementation is its slowness when zooming out and showing lots of items simultaneously.

My idea to get around this bottleneck is to render an image of the matrix when the zoom-out level is such that the exact details won't anyway be shown, and scale that pixmap to zoom further out. When zooming in, the pixmap would be replaced by the individually drawn tiles. This is my idea but I don't know how to do that. I'm quite sure it's doable and possibly someone has already done something similar. Can you give links to existing code or suggestions how you would do it. If you know a much better way to get around this zooming problem, I'd obviously be very happy to hear about that.

I've attached code that generates dummy data and displays these in a browser window. When you zoom out (Ctrl+mouse wheel) you can see that the scaling isn't smooth and the application becomes unresponsive.

Thanks a lot for any help!


#include <qapplication.h>
#include <qmainwindow.h>
#include <qgraphicsview.h>
#include <qgraphicsscene.h>
#include <qgraphicsitem.h>
#include <QWheelEvent>
#include <QtOpenGL>
#include <qmath.h>
#include <qcolor.h>

using namespace std;


class BaseTile : public QGraphicsItem
{
public:
BaseTile(int i);
QRectF boundingRect() const{ return QRectF(0, 0, 20, 20); }

void paint(QPainter *painter, const QStyleOptionGraphicsItem *item, QWidget *widget);
private:
QColor color;
QChar base_char;
};


class MainWindow : public QMainWindow
{
public:
MainWindow(QWidget *parent = 0);
private:
void wheelEvent(QWheelEvent * event);

QGraphicsScene *scene;
QGraphicsView *graphicsView;
};

/////////////////////

BaseTile::BaseTile(int i)
{
QString alpha = "ACGT";
QColor tile_colors[] = { QColor("blue"), QColor("green"), QColor("yellow"), QColor("red") };

base_char = alpha.at(i);
color = tile_colors[i];
}

void BaseTile::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(widget);

const qreal lod = option->levelOfDetailFromTransform(painter->worldTransform());
if (lod < 0.5) {
painter->fillRect(QRectF(0, 0, 20, 20), color);
return;
}

QBrush b = painter->brush();
painter->fillRect(QRectF(0, 0, 20, 20), color);
painter->setFont(QFont("Times",10));
painter->setPen(QColor("black"));
painter->drawText(0, 0, 20, 20,0x0084, QString(base_char));
}

/////////////////////

void MainWindow::wheelEvent(QWheelEvent * e)
{
if ( e->modifiers() == Qt::ControlModifier )
{
int numSteps = ( e->delta() / 8 ) / 15;

QMatrix mat = graphicsView->matrix();

if ( numSteps > 0 )
mat.scale( numSteps * 1.2, numSteps * 1.2 );
else
mat.scale( -1 / ( numSteps * 1.2 ), -1 / ( numSteps * 1.2 ) );

graphicsView->setMatrix(mat);
e->accept();
}
}

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{

// generate random data to display
//
vector< vector<int> > data;
int seq_length = 5000;
int num_seq = 80;

vector<int> seq0;
for(int j=0;j<seq_length;j++)
{
seq0.push_back( int(rand()/float(RAND_MAX)*4) );
}
data.push_back(seq0);

for(int i=1;i<num_seq;i++)
{
vector<int> seq_i;
for(int j=0;j<seq_length;j++)
{
if(rand()/float(RAND_MAX)*20 < 1)
seq_i.push_back( int(rand()/float(RAND_MAX)*4) );
else
seq_i.push_back( data.at(0).at(j) );
}
data.push_back(seq_i);
}



// the browser stuff
//
scene = new QGraphicsScene();

int y_pos = 0;
for (int i = 0; i < num_seq; i++)
{
int x_pos = 0;

for (int j = 0; j < seq_length; j++)
{
int base = data.at(i).at(j);

BaseTile *item = new BaseTile(base);
item->setPos(QPointF(x_pos, y_pos));
scene->addItem(item);

x_pos += 20;
}
y_pos += 20;
}


graphicsView = new QGraphicsView(this);
graphicsView->setRenderHint(QPainter::Antialiasing, false);
graphicsView->setDragMode(QGraphicsView::ScrollHandDrag);
graphicsView->setOptimizationFlags(QGraphicsView::DontSavePainte rState);
graphicsView->setViewportUpdateMode(QGraphicsView::SmartViewport Update);
graphicsView->setTransformationAnchor(QGraphicsView::AnchorUnder Mouse);
graphicsView->setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));
graphicsView->setScene(scene);
graphicsView->setGeometry(QRect(50, 50, 100, 100));
graphicsView->show();


this->setCentralWidget(graphicsView);

}

/////////////////////

int main(int argc, char *argv[])
{
QApplication a(argc, argv);

MainWindow w;
w.show();
return a.exec();
}

/////////////////////

/*
g++ -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4/QtOpenGL -I/usr/include/qt4 -L/usr/lib -lQtOpenGL -lQtGui -lQtCore -lGLU -lGL -lpthread test.cpp -o test
*/

JohannesMunk
19th April 2010, 16:22
Hi Lari!

Rendering Text is slow. And you have only for different characters / items to draw. Why don't you render 4 textures at programm startup? QImage, QPainter => QGLWidget::bindTexture.

Then I would use only one QGraphicsItem that draws all visible data by drawing the textures to appropriate positions - QGLWidget::drawTexture

Should be quite quick to implement and see if the performance is good enough!

Johannes

lari
19th April 2010, 22:32
Hi Johannes!

That's an interesting idea but unfortunately I have zero experience on QGLWidgets and can't do even a "trivial" thing like that. I understand the idea of making a set of images (I tested a version that draws pre-defined QPixmaps on GraphicsScene instead of GraphicsItem objects) but don't know how to create textures and then draw those on GraphicsScene. Can you give more detailed code for those bits, please.

Thanks a lot in advance!

Regards, Lari

JohannesMunk
20th April 2010, 00:12
Hi Lari!

I just looked into the matter with more detail: Qt's OpenGL Painter automatically assigns textures to QPixmaps. So when you repaint the same Pixmap over and over again, this should be blazing fast.

Due to this http://bugreports.qt.nokia.com/browse/QTBUG-6800 it wont be possible to use the low-level- bindtexture/drawtexture with the painter setup to the view, if I understand that correctly. So you would have to implement zooming and scrolling manually.

How fast is the version with the pre-defined QPixmaps? If you share the code, i'll have a look at it. Maybe you can optimize the paint method of the big item to only show those items, whose coordinates are within the visible scenerect.

Joh

JohannesMunk
20th April 2010, 03:28
Ok.. I wanted to see how far this could go.. and implemented a low-level GL solution. It's a bit messy.. just wanted to check it out. Prerendering the sequences to big display lists doesn't give a speed boost and introduces problems with empty displaylists, if the gl context runs out of memory (?).

That's as far as brute force optimization goes, I think. Further optimizations can be achieved by only drawing the visible items or rendering a big pixmap if the detail level drops to a resolution that can be handled. Both together should allow for a smooth user interaction. To see what items are to be drawn you could look into glUnproject.



#ifndef MAINGL_H
#define MAINGL_H

#include <QtOpenGL>

class MainWindow : public QGLWidget
{ Q_OBJECT
public:
MainWindow(QWidget *parent = 0,int seq_length = 5000,int num_seq = 80) : QGLWidget(parent)
{
// generate random data to display
data.reserve(num_seq);
QVector<quint8> seq0;
seq0.reserve(seq_length);
for(int j=0;j<seq_length;j++)
{
seq0.push_back( int(rand()/float(RAND_MAX)*4) );
}
data.push_back(seq0);

for(int i=1;i<num_seq;i++)
{
QVector<quint8> seq_i;
seq_i.reserve(seq_length);
for(int j=0;j<seq_length;j++)
{
if(rand()/float(RAND_MAX)*20 < 1)
seq_i.push_back( int(rand()/float(RAND_MAX)*4) );
else
seq_i.push_back( data.at(0).at(j) );
}
data.push_back(seq_i);
}
camPos[0] = 0;camPos[1] = num_seq*10;camPos[2] = 2000;
totaldisplaylist = 0;
totaldisplaylistcount = 0;
gldisplist = 0;
}
~MainWindow()
{
for (quint8 i=0;i < 4;++i) deleteTexture(gltextures[i]);
if (totaldisplaylist) glDeleteLists(totaldisplaylist,totaldisplaylistcou nt);
if (gldisplist) glDeleteLists(gldisplist,4);
}

protected:

void initializeGL()
{
// Set up the rendering context, define display lists etc.:
glClearColor(1.0, 1.0, 1.0, 1.0);
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

QString alpha = "ACGT";
QColor tile_colors[] = { QColor("blue"), QColor("green"), QColor("yellow"), QColor("red") };
// Generate 4 consecutive displaylists
gldisplist = glGenLists(4);
// Prepare 4 textures
for (quint8 i=0;i < 4;++i)
{
QChar base_char = alpha.at(i);
QColor color = tile_colors[i];
QPixmap* pmap = new QPixmap(20,20);
textures[i] = pmap;
QPainter painter(pmap);
painter.fillRect(QRectF(0, 0, 20, 20), color);
painter.setFont(QFont("Times",10));
painter.setPen(QColor("black"));
painter.drawText(0, 0, 20, 20,0x0084, QString(base_char));
gltextures[i] = bindTexture(*pmap);
qDebug() << gltextures[i];

// compile display list
glNewList(gldisplist+i, GL_COMPILE);
{
glBindTexture(GL_TEXTURE_2D, gltextures[i]);

glBegin(GL_QUADS);

// Upper right corner
glTexCoord2f(0.0, 1.0);
glVertex3f(0.0, 20, 0.0);

// Upper right corner
glTexCoord2f(1.0, 1.0);
glVertex3f(20, 20, 0.0);

// Lower right corner
glTexCoord2f(1.0, 0.0);
glVertex3f(20, 0.0, 0.0);

// Lower left corner
glTexCoord2f(0.0, 0.0);
glVertex3f(0.0, 0.0, 0.0);
glEnd();
}
glEndList();
}
prerender = false;
if (prerender)
renderGL();
}

void resizeGL(int w, int h)
{
// setup viewport, projection etc.:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, (GLint)w, (GLint)h);
gluPerspective(70.0, (float)w/(float)h, 0.01f, 100000.0f);
//glOrtho(1,w,1,h,-1,10);
}

void renderGL()
{
if (totaldisplaylist) glDeleteLists(totaldisplaylist,totaldisplaylistcou nt);
totaldisplaylistcount = data.size();
totaldisplaylist = glGenLists(totaldisplaylistcount);
float x_inc = 20;
float y_inc = 20;
for (int i = 0; i < data.size(); i++)
{
glNewList(totaldisplaylist+i, GL_COMPILE);
{
QVector<quint8> seq = data.at(i);
for (int j = 0; j < seq.size(); j++)
{
glCallList(gldisplist+seq.at(j));
glTranslatef(20,0,0);
}
glTranslatef(-x_inc*seq.size(),y_inc,0);
}
glEndList();
}
}

void paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Setup camera ..
gluLookAt(camPos[0],camPos[1],camPos[2],camPos[0],camPos[1],camPos[2]-500,0,1,0);
if (prerender) {
// draw the scene:
for (int i = 0; i < data.size(); i++)
{
glCallList(totaldisplaylist+i);
}
} else {
float x_inc = 20;
float y_inc = 20;
for (int i = 0; i < data.size(); i++)
{
QVector<quint8> seq = data.at(i);
for (int j = 0; j < seq.size(); j++)
{
glCallList(gldisplist+seq.at(j));
glTranslatef(20,0,0);
}
glTranslatef(-x_inc*seq.size(),y_inc,0);
}
}
}

void keyPressEvent(QKeyEvent *event)
{
// CAMERA
if ((event->modifiers() == Qt::NoModifier) || (event->modifiers() == Qt::ShiftModifier))
{
qreal delta = 50;
if (event->modifiers() == Qt::ShiftModifier) delta *= 10;
switch (event->key()) {
case Qt::Key_Left : {camPos[0] -= delta;}; break;
case Qt::Key_A : {camPos[0] -= delta;}; break;
case Qt::Key_Right : {camPos[0] += delta;}; break;
case Qt::Key_D : {camPos[0] += delta;}; break;
case Qt::Key_Down : {camPos[1] += delta;}; break;
case Qt::Key_W : {camPos[1] += delta;}; break;
case Qt::Key_Up : {camPos[1] -= delta;}; break;
case Qt::Key_S : {camPos[1] -= delta;}; break;
case Qt::Key_Q : {camPos[2] -= delta;}; break;
case Qt::Key_E : {camPos[2] += delta;}; break;
}
update();
}
}
private:
// The 4 characters
QPixmap* textures[4];
GLuint gltextures[4];
GLuint gldisplist;
// Each sequence as a displaylist
GLuint totaldisplaylist;
int totaldisplaylistcount;
float camPos[3];
bool prerender;
QVector< QVector<quint8> > data;
};

#endif // MAINGL_H

-------------------------------

#include <QtCore>
#include <QtGui>

#include "maingl.h"

int main(int argc, char *argv[])
{
QApplication a(argc, argv);

MainWindow w;
w.show();
return a.exec();
}

Hope it helps!

Johannes

lari
20th April 2010, 11:24
Hi Johannes!

Thanks a lot for your effort! I need time digest all the new stuff (and any serious attempt has to wait after the grant application deadline) but your example makes eager to learn more about GL.

I got your code compiling on my Ubuntu system but its performance isn't what I expected. I had to reduce the matrix size to something like 30x100 to make it reasonably fast and even then it sometimes used quite a lot of CPU. I suppose that my hardware acceleration works: glxgears gives some 4500 frames in 5 sec and, with my earlier appraoch, adding "graphicsView->setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));" massively improved the performance.

I wonder if I'm missing something very obvious. This is my project file:



QT += opengl
TARGET = qab
TEMPLATE = app
CONFIG += release
HEADERS += maingl.h
SOURCES += main.cpp


Should I have something more there?

Thanks!

Lari

JohannesMunk
20th April 2010, 12:49
Hi Lari!

No, your project file looks good. I was too tired yesterday night. There is a big speed improvement with prerendering. Just set the bool in the code to true. I don't know how I could miss that :-> But it works correctly only up to a seq_lenght of ~1800.

And if compared to a QGraphicsView solution it doesn't gain much, if anything. I'm puzzled. My graphicsview solution crashes (only in release mode) if I try to increase the seq_length to 1900. Don't know whats wrong. That seems to be the same limit, my low-level solution has, before it starts to mess up. So my guess is, that the graphicsview also prerenders the whole item into a displaylist.. hence its excellent performance!

BTW: I'm using Qt4.6 on Win7 with an ATI3850,AMD X2 6000+.



#ifndef MAIN_H
#define MAIN_H

#include <qapplication.h>
#include <qmainwindow.h>
#include <qgraphicsview.h>
#include <qgraphicsscene.h>
#include <qgraphicsitem.h>
#include <QWheelEvent>
#include <QtOpenGL>
#include <qmath.h>
#include <qcolor.h>

using namespace std;


class SeqMap : public QGraphicsItem
{
public:
SeqMap(int seq_length = 1500,int num_seq = 80);
QRectF boundingRect() const{ return QRectF(0, 0, data.at(0).size()*20, data.size()*20); }

void paint(QPainter *painter, const QStyleOptionGraphicsItem *item, QWidget *widget);
private:
QPixmap* textures[4];
QVector< QVector<quint8> > data;
};


class MainWindow : public QMainWindow
{
public:
MainWindow(QWidget *parent = 0);
private:
void wheelEvent(QWheelEvent * event);

QGraphicsScene *scene;
QGraphicsView *graphicsView;
};

/////////////////////

SeqMap::SeqMap(int seq_length,int num_seq)
{
// generate random data to display
data.reserve(num_seq);
QVector<quint8> seq0;
seq0.reserve(seq_length);
for(int j=0;j<seq_length;j++)
{
seq0.push_back( int(rand()/float(RAND_MAX)*4) );
}
data.push_back(seq0);

for(int i=1;i<num_seq;i++)
{
QVector<quint8> seq_i;
seq_i.reserve(seq_length);
for(int j=0;j<seq_length;j++)
{
if(rand()/float(RAND_MAX)*20 < 1)
seq_i.push_back( int(rand()/float(RAND_MAX)*4) );
else
seq_i.push_back( data.at(0).at(j) );
}
data.push_back(seq_i);
}

QString alpha = "ACGT";
QColor tile_colors[] = { QColor("blue"), QColor("green"), QColor("yellow"), QColor("red") };
// Prepare 4 textures
for (quint8 i=0;i < 4;++i)
{
QChar base_char = alpha.at(i);
QColor color = tile_colors[i];
QPixmap* pmap = new QPixmap(20,20);
textures[i] = pmap;
QPainter painter(pmap);
QBrush b = painter.brush();
painter.fillRect(QRectF(0, 0, 20, 20), color);
painter.setFont(QFont("Times",10));
painter.setPen(QColor("black"));
painter.drawText(0, 0, 20, 20,0x0084, QString(base_char));
}
}

void SeqMap::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(widget);

int y_pos = 0;
for (int i = 0; i < data.size(); i++)
{
int x_pos = 0;

for (int j = 0; j < data.at(i).size(); j++)
{
int base = data.at(i).at(j);
painter->drawPixmap(x_pos,y_pos,*textures[base]);
x_pos += 20;
}
y_pos += 20;
}
}

/////////////////////

void MainWindow::wheelEvent(QWheelEvent * e)
{
if ( e->modifiers() == Qt::ControlModifier )
{
int numSteps = ( e->delta() / 8 ) / 15;

QMatrix mat = graphicsView->matrix();

if ( numSteps > 0 )
mat.scale( numSteps * 1.2, numSteps * 1.2 );
else
mat.scale( -1 / ( numSteps * 1.2 ), -1 / ( numSteps * 1.2 ) );

graphicsView->setMatrix(mat);
e->accept();
}
}

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{

// the browser stuff
scene = new QGraphicsScene();
scene->addItem(new SeqMap());

graphicsView = new QGraphicsView(this);
graphicsView->setRenderHint(QPainter::Antialiasing, false);
graphicsView->setDragMode(QGraphicsView::ScrollHandDrag);
graphicsView->setOptimizationFlags(QGraphicsView::DontSavePainte rState);
graphicsView->setViewportUpdateMode(QGraphicsView::SmartViewport Update);
graphicsView->setTransformationAnchor(QGraphicsView::AnchorUnder Mouse);
graphicsView->setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));
graphicsView->setScene(scene);
graphicsView->setGeometry(QRect(50, 50, 100, 100));
graphicsView->show();

this->setCentralWidget(graphicsView);

}

#endif // MAIN_H

---------------------------------

#include <QtCore>
#include <QtGui>

#include "main.h"

int main(int argc, char *argv[])
{
QApplication a(argc, argv);

MainWindow w;
w.show();
return a.exec();
}
I'll have to leave this to you. Gotta do my stuff now :->

Good luck,

Johannes

JohannesMunk
20th April 2010, 13:37
Couldn't leave it :->

I implemented the two optimizations I mentioned before:



#ifndef MAIN_H
#define MAIN_H

#include <qapplication.h>
#include <qmainwindow.h>
#include <qgraphicsview.h>
#include <qgraphicsscene.h>
#include <qgraphicsitem.h>
#include <QWheelEvent>
#include <QtOpenGL>
#include <qmath.h>
#include <qcolor.h>

using namespace std;


class SeqMap : public QGraphicsItem
{
public:
SeqMap(int seq_length = 20000,int num_seq = 80);
QRectF boundingRect() const{ return QRectF(0, 0, data.at(0).size()*20, data.size()*20); }

int seq_length() {return data.at(0).size();}
int num_seq() {return data.size();}

void paint(QPainter *painter, const QStyleOptionGraphicsItem *item, QWidget *widget);
private:
QPixmap* textures[4];
QVector< QVector<quint8> > data;
};


class MainWindow : public QMainWindow
{
public:
MainWindow(QWidget *parent = 0);
private:
void wheelEvent(QWheelEvent * event);

double scale;
SeqMap* seqmap;
QGraphicsScene *scene;
QGraphicsView *graphicsView;
};

/////////////////////

SeqMap::SeqMap(int seq_length,int num_seq)
{
// Need this for exposedRect to be initialized!
setFlag(QGraphicsItem::ItemUsesExtendedStyleOption ,true);
// generate random data to display
data.reserve(num_seq);
QVector<quint8> seq0;
seq0.reserve(seq_length);
for(int j=0;j<seq_length;j++)
{
seq0.push_back( int(rand()/float(RAND_MAX)*4) );
}
data.push_back(seq0);

for(int i=1;i<num_seq;i++)
{
QVector<quint8> seq_i;
seq_i.reserve(seq_length);
for(int j=0;j<seq_length;j++)
{
if(rand()/float(RAND_MAX)*20 < 1)
seq_i.push_back( int(rand()/float(RAND_MAX)*4) );
else
seq_i.push_back( data.at(0).at(j) );
}
data.push_back(seq_i);
}

QString alpha = "ACGT";
QColor tile_colors[] = { QColor("blue"), QColor("green"), QColor("yellow"), QColor("red") };
// Prepare 4 textures
for (quint8 i=0;i < 4;++i)
{
QChar base_char = alpha.at(i);
QColor color = tile_colors[i];
QPixmap* pmap = new QPixmap(20,20);
textures[i] = pmap;
QPainter painter(pmap);
QBrush b = painter.brush();
painter.fillRect(QRectF(0, 0, 20, 20), color);
painter.setFont(QFont("Times",10));
painter.setPen(QColor("black"));
painter.drawText(0, 0, 20, 20,0x0084, QString(base_char));
}
}

void SeqMap::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(widget);
// Use the exposedRect
int start_x = max(0,(int)option->exposedRect.left()/20-1);
int end_x = min(data.at(0).size(),(int)option->exposedRect.right()/20+1);
int start_y = max(0,(int)option->exposedRect.top()/20-1);
int end_y = min(data.size(),(int)option->exposedRect.bottom()/20+1);

int y_pos = 0;
for (int i = start_y; i < end_y; i++)
{
int x_pos = start_x*20;

for (int j = start_x; j < end_x; j++)
{
quint8 base = qMin((quint8)3,data.at(i).at(j));
painter->drawPixmap(x_pos,y_pos,*textures[base]);
x_pos += 20;
}
y_pos += 20;
}
}

/////////////////////

void MainWindow::wheelEvent(QWheelEvent * e)
{
if ( e->modifiers() == Qt::ControlModifier )
{
int numSteps = ( e->delta() / 8 ) / 15;

double tempscale = 1;
if ( numSteps > 0 )
tempscale *= numSteps*1.2;
else
tempscale *= -1/(numSteps*1.2);
scale *= tempscale;

QMatrix mat = graphicsView->matrix();
mat.scale(tempscale,tempscale);
graphicsView->setMatrix(mat);
e->accept();
}
if (scale < 0.10)
seqmap->setCacheMode(QGraphicsItem::ItemCoordinateCache,QS ize(min(seqmap->seq_length(),8000),min(seqmap->num_seq(),2000)));
else
seqmap->setCacheMode(QGraphicsItem::NoCache);
}

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
QPixmapCache::setCacheLimit(100000);
scale = 1.0;
// the browser stuff
scene = new QGraphicsScene();
seqmap = new SeqMap();
scene->addItem(seqmap);

graphicsView = new QGraphicsView(this);
graphicsView->setRenderHint(QPainter::Antialiasing, false);
graphicsView->setDragMode(QGraphicsView::ScrollHandDrag);
graphicsView->setOptimizationFlags(QGraphicsView::DontSavePainte rState);
graphicsView->setViewportUpdateMode(QGraphicsView::SmartViewport Update);
graphicsView->setTransformationAnchor(QGraphicsView::AnchorUnder Mouse);
graphicsView->setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));
graphicsView->setScene(scene);
graphicsView->setGeometry(QRect(50, 50, 100, 100));
graphicsView->show();

this->setCentralWidget(graphicsView);

}

#endif // MAIN_H


Good luck!

Johannes

JohannesMunk
20th April 2010, 13:55
AAAH! Origin to both bugs is your random data.. there is of course sometimes a 4 inside!!

int(rand()/float(RAND_MAX)*4).

As the random generator is deterministic without initialization.. this always occured at the same value..

quick fix: quint8 base = qMin((quint8)3,data.at(i).at(j)); in the paint method

So now everything works.. and blazing fast :->

Good luck for your project!

Johannes

lari
20th April 2010, 13:58
Thanks a lot! This is a good start for me start experimenting! ;)

JohannesMunk
20th April 2010, 14:09
I updated the code above once more. It supports bigger cache pixmaps now. You got to adapt this to your needs though!

Johannes

BTW: If you don't mind, you could use the forums thank button :->

lari
21st April 2010, 11:58
Hi Johannes,

You are righth, it is blazing fast for moving around and zooming in/out on moderate zoom levels. However, my old hardware (ATI Radeon Mobility X1400), or the Linux drivers for it, may not be good enough to zoom out to see the whole matrix.

This is a great piece of code but also so advanced (to me at least) that I need to do some studying to be able to continue from this. I hope that this leads to a real application one day: I've dreamed of a project where I could learn some nice Qt programming but I also feel that the project has to be related to my research work to be justified. This is exactly that!

Lari

P.S. Sorry about the bug! Wasn't first time that I got rand() limits wrong...

JohannesMunk
21st April 2010, 12:21
Hi Lari!

If your hardware is too slow, just reduce the maximum resolution of the cached item in line 39. The last parameter is the size of the cache for that item. But if you set it below the sequence lenght, you won't see every 'step' any more, though! You can also vary the threshold value in line 38, to change when the two display modes are switched.

What is more advanced here, than in your code? If you have any questions about it, you are welcome to ask!

Don't worry about the bug - happens to everyone. Funny was, what wrong explanation I found for the misbehaviour :->

Let me know how your project advances. I am interested in were you go with it.

Happy coding,

Johannes