14 #include "qui/PathScene.hpp"
15 #include "alg/glsequence.hpp"
16 #include "mussa_exceptions.hpp"
20 PathScene::PathScene(Mussa* analysis, QWidget *parent) :
26 maxOrtho2d(-50.0, -50, 3000000.0, 300.0),
27 curOrtho2d(maxOrtho2d),
28 viewport_center(((curOrtho2d.right()-curOrtho2d.left())/2)+curOrtho2d.left()),
35 mussaAnalysis = new Mussa;
39 mussaAnalysis = analysis;
44 QSize PathScene::sizeHint() const
46 return QSize(400, 400);
49 float PathScene::left()
51 return maxOrtho2d.left();
54 float PathScene::right()
56 return maxOrtho2d.right();
59 float PathScene::viewportLeft()
61 return curOrtho2d.left();
64 float PathScene::viewportRight()
66 return curOrtho2d.right();
69 float PathScene::viewportCenter()
71 return viewport_center;
74 void PathScene::updateViewport(float center, int new_zoom)
76 float max_width = maxOrtho2d.width();
77 if (new_zoom < 1) new_zoom = 1;
78 float new_max_width = max_width / new_zoom;
79 //curOrtho2d.setLeft(max(center-new_max_width, maxOrtho2d.left()));
80 //curOrtho2d.setRight(min(center+new_max_width, maxOrtho2d.right()));
81 curOrtho2d.setLeft(center-new_max_width);
82 curOrtho2d.setRight(center+new_max_width);
83 emit viewportChanged();
86 void PathScene::setViewportX(float x)
88 //hopefully this calculates a sufficiently reasonable == for a float
89 if (x != viewport_center )
91 updateViewport(x, zoom);
97 void PathScene::setZoom(int new_zoom)
99 if (zoom != new_zoom) {
100 // try to figure out where we should be now?
101 updateViewport(viewport_center, new_zoom);
107 void PathScene::setClipPlane(int newZ)
109 if (clipZ != (double) newZ){
110 clipZ = (double) newZ;
115 void PathScene::loadMotifList()
117 QString caption("Load a motif list");
118 QString filter("Motif list(*.txt *.mtl)");
119 QString path = QFileDialog::getOpenFileName(this,
126 // try to load safely
128 mussaAnalysis->load_motifs(path.toStdString());
130 } catch (runtime_error e) {
131 QString msg("Unable to load ");
135 QMessageBox::warning(this, "Load Motifs", msg);
137 assert (mussaAnalysis != 0);
139 void PathScene::loadMupa()
141 QString caption("Load a mussa parameter file");
142 QString filter("Mussa Parameters (*.mupa)");
143 QString mupa_path = QFileDialog::getOpenFileName(this,
148 if (mupa_path.isNull())
150 // try to load safely
152 Mussa *m = new Mussa;
153 m->load_mupa_file(mupa_path.toStdString());
154 m->analyze(0, 0, Mussa::TransitiveNway, 0.0);
155 // only switch mussas if we loaded without error
156 delete mussaAnalysis;
159 } catch (mussa_load_error e) {
160 QString msg("Unable to load ");
164 QMessageBox::warning(this, "Load Parameter", msg);
166 assert (mussaAnalysis != 0);
169 void PathScene::loadSavedAnalysis()
171 QString caption("Load a previously run analysis");
172 QString muway_dir = QFileDialog::getExistingDirectory(this,
174 QDir::currentPath());
176 if (muway_dir.isNull())
178 // try to safely load
180 Mussa *m = new Mussa;
181 m->load(muway_dir.toStdString());
182 // only switch mussas if we loaded without error
183 delete mussaAnalysis;
186 } catch (mussa_load_error e) {
187 QString msg("Unable to load ");
191 QMessageBox::warning(this, "Load Parameter", msg);
193 assert (mussaAnalysis != 0);
196 void PathScene::setSoftThreshold(int threshold)
198 if (mussaAnalysis->get_threshold() != threshold) {
199 mussaAnalysis->set_soft_thres(threshold);
200 mussaAnalysis->nway();
207 void PathScene::initializeGL()
209 glEnable(GL_DEPTH_TEST);
210 glClearColor(1.0, 1.0, 1.0, 0.0);
211 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
212 glShadeModel(GL_FLAT);
215 void PathScene::resizeGL(int width, int height)
217 viewport_width = width;
218 viewport_height = height;
219 assert (geometry().width() == width);
220 assert (geometry().height() == height);
221 glViewport(0, 0, (GLsizei)width, (GLsizei)height);
222 glMatrixMode(GL_PROJECTION);
224 // I'm abusing this as Qt and OpenGL disagree about the direction of the
226 glOrtho(curOrtho2d.left(), curOrtho2d.right(),
227 curOrtho2d.top(), curOrtho2d.bottom(),
231 void PathScene::paintGL()
233 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
236 glMatrixMode(GL_PROJECTION);
238 glOrtho(curOrtho2d.left(), curOrtho2d.right(),
239 curOrtho2d.top(), curOrtho2d.bottom(),
241 glMatrixMode(GL_MODELVIEW);
244 glDepthMask(GL_FALSE);
245 if (selectedMode && !drawingBand) {
246 glColor4f(0.6, 0.6, 0.6, 0.9);
247 glRectf(previousBand.x(), previousBand.y(),
248 previousBand.right(), previousBand.bottom());
250 glDepthMask(GL_TRUE);
256 void PathScene::updateScene()
258 // Delete old glsequences
259 // FIXME: does this actually free the memory from the new'ed GlSequences?
262 // save a reference to our GlSequences
264 float y = mussaAnalysis->sequences().size() * 100 ;
265 float max_base_pairs = 0;
266 typedef vector<Sequence>::const_iterator seqs_itor_t;
267 for(seqs_itor_t seq_itor = mussaAnalysis->sequences().begin();
268 seq_itor != mussaAnalysis->sequences().end();
272 gl_seq = new GlSequence(*seq_itor, mussaAnalysis->colorMapper());
275 if (gl_seq->length() > max_base_pairs ) max_base_pairs = gl_seq->length();
276 tracks.push_back( *gl_seq );
278 maxOrtho2d.setWidth(max_base_pairs + 100.0);
279 maxOrtho2d.setHeight((mussaAnalysis->sequences().size()) * 100 );
280 curOrtho2d = maxOrtho2d;
281 viewport_center = (curOrtho2d.right()-curOrtho2d.left())/2+curOrtho2d.left();
284 void PathScene::processSelection(GLuint hits, GLuint buffer[], GLuint bufsize)
286 const size_t pathz_count = mussaAnalysis->paths().refined_pathz.size();
294 selectedPaths.clear();
295 selectedPaths.reserve(pathz_count);
296 selectedPaths.insert(selectedPaths.begin(), pathz_count, false);
297 selectedTrack = 0x7fffffff;
299 std::cout << "hits = " << hits << " " << pathz_count << std::endl;
300 ptr = (GLuint *) buffer;
303 for (GLuint i=0; i < hits; ++i)
305 if ((i + 5) > bufsize) {
306 std::clog << "*** selection overflow***" << std::endl;
309 z1 = ((float)*ptr++)/0x7fffffff;
310 z2 = ((float)*ptr++)/0x7fffffff;
314 std::clog << "wrong number of glNames, selection is having trouble ";
315 std::clog << " got " << names << std::endl;
316 std::clog << " names: " ;
317 for (GLuint j = 0 ; j < names-2; ++j) {
318 std::clog << *ptr++ << " ";
325 selectedPaths[objid] = true;
328 if (objid < selectedTrack) {
329 selectedTrack = objid;
337 void PathScene::mousePressEvent( QMouseEvent *e)
340 std::cout << "x=" << e->x() << " y=" << e->y() << std::endl;
342 selectedMode = false;
343 bandOrigin = e->pos();
345 rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
347 rubberBand->setGeometry(QRect(bandOrigin, QSize()));
351 void PathScene::mouseMoveEvent( QMouseEvent *e)
354 rubberBand->setGeometry(QRect(bandOrigin, e->pos()).normalized());
357 void dumpRect(const QRect &r)
359 std::cout << "x=" << r.x() << " y=" << r.y()
360 << " w=" << r.width() << " h=" << r.height() << std::endl;
363 void PathScene::mouseReleaseEvent( QMouseEvent *e)
367 QRect r = QRect(bandOrigin, e->pos()).normalized();
368 bandOrigin = r.topLeft();
369 std::cout << "band ";
372 std::cout << "window ";
373 dumpRect(geometry());
375 GLfloat x_scale = curOrtho2d.width()/((float)geometry().width());
376 GLfloat y_scale = curOrtho2d.height()/((float)geometry().height());
377 GLfloat x_left = curOrtho2d.left() + (r.x()*x_scale);
378 GLfloat x_right = x_left + r.width() * x_scale;
379 // using QRectF with Y axis swapped
380 GLfloat y_top = curOrtho2d.bottom()-(r.y()*y_scale);
381 GLfloat y_bottom = y_top - r.height() * y_scale;
382 previousBand.setCoords(x_left, y_top, x_right, y_bottom);
383 std::cout << x_left << " " << x_right << " " << y_top << " " << y_bottom
386 // hopefully this will make a buffer big enough to receive
387 // everything being selected
388 const size_t pathz_count = mussaAnalysis->paths().refined_pathz.size();
389 const GLuint select_buf_size = 1 + 5 * (pathz_count + tracks.size()) ;
390 GLuint selectBuf[select_buf_size];
391 glSelectBuffer(select_buf_size, selectBuf);
394 (void)glRenderMode(GL_SELECT);
396 glMatrixMode(GL_PROJECTION);
398 glOrtho(x_left, x_right, y_top, y_bottom, -50.0, 50.0);
399 glMatrixMode(GL_MODELVIEW);
406 hits = glRenderMode(GL_RENDER);
407 processSelection(hits, selectBuf, select_buf_size);
409 resizeGL(geometry().width(), geometry().height());
414 // openGl rendering code
416 void PathScene::draw_tracks() const
420 for (vector<GlSequence>::size_type i = 0; i != tracks.size(); ++i )
423 tracks[i].draw(curOrtho2d.left(), curOrtho2d.right());
429 void PathScene::draw_lines() const
435 bool reversed = false;
436 bool prevReversed = false;
437 const NwayPaths& nway = mussaAnalysis->paths();
441 vector<GlSequence>::const_iterator track_itor;
443 typedef list<ExtendedConservedPath> conserved_paths;
444 typedef conserved_paths::const_iterator const_conserved_paths_itor;
445 for(const_conserved_paths_itor path_itor = nway.refined_pathz.begin();
446 path_itor != nway.refined_pathz.end();
447 ++path_itor, ++objid)
449 track_itor = tracks.begin();
450 // since we were drawing to the start of a window, and opengl lines
451 // are centered around the two connecting points our lines were slightly
452 // offset. the idea of window_offset is to adjust them to the
453 // right for forward compliment or left for reverse compliment
454 // FIXME: figure out how to unit test these computations
455 GLfloat window_offset = (path_itor->window_size)/2.0;
457 glBegin(GL_LINE_STRIP);
458 for (vector<int>::const_iterator sp_itor = path_itor->begin();
459 sp_itor != path_itor->end();
460 ++sp_itor, ++track_itor)
464 // at some point when we modify the pathz data structure to keep
465 // track of the score we can put grab the depth here.
467 // are we reverse complimented?
472 x = -x; // make positive
475 x += window_offset; // move right for forward compliment
477 x -= window_offset; // move left for reverse compliment
478 // the following boolean implements logical xor
479 if ( (reversed || prevReversed) && (!reversed || !prevReversed)) {
480 // we have a different orientation
481 if (not selectedMode or selectedPaths[objid] == true) {
482 // if we have nothing selected, or we're the highlight, be bright
483 glColor3f(0.0, 0.0, 1.0);
486 glColor3f(0.7, 0.7, 1.0);
489 // both current and previous path have the same orientation
490 if (not selectedMode or selectedPaths[objid] == true) {
491 glColor3f(1.0, 0.0, 0.0);
493 glColor3f(1.0, 0.7, 0.7);
496 prevReversed = reversed;
497 glVertex3f(x, y, -1.0);
500 glLoadName(++pathid);
505 GLuint PathScene::make_line_list()
507 GLuint line_list = glGenLists(1);
508 glNewList(line_list, GL_COMPILE);
517 void PathScene::mussaesque()
519 //static GLuint theLines = make_line_list();
522 glPushName(MussaPaths);
523 //glCallList(theLines);
525 glLoadName(MussaTracks);