16 #include "qui/GlSequence.h"
20 PathScene::PathScene(Mussa* analysis, QWidget *parent) :
26 maxOrtho2d(-50.0, -50, 3000000.0, 300.0),
27 curOrtho2d(maxOrtho2d),
34 mussaAnalysis = new Mussa;
38 mussaAnalysis = analysis;
43 QSize PathScene::sizeHint() const
45 return QSize(400, 400);
48 static float max(float a, float b)
56 static float min(float a, float b)
64 void PathScene::setZoom(int newZoom)
66 std::cout << newZoom << " " << zoom << std::endl;
67 if (zoom != newZoom) {
68 // try to figure out where we should be now?
70 float width = maxOrtho2d.width();
71 std::cout << "max width " << width
72 << " max left " << maxOrtho2d.left()
73 << " max right " << maxOrtho2d.right() << std::endl;
74 float newWidth = width / newZoom;
75 std::cout << "new width" << newWidth<< std::endl;
76 float center = curOrtho2d.width()/2 + curOrtho2d.left();
77 std::cout << "l: " << curOrtho2d.left() << " r: " << curOrtho2d.right()
78 << " ctr: " << center << std::endl;
79 curOrtho2d.setLeft(max(center-newWidth, maxOrtho2d.left()));
80 curOrtho2d.setRight(min(center+newWidth, maxOrtho2d.right()));
81 std::cout << "nl: " << curOrtho2d.left() << " nr: " << curOrtho2d.right()
88 void PathScene::setClipPlane(int newZ)
90 if (clipZ != (double) newZ){
91 clipZ = (double) newZ;
96 void PathScene::loadMupa()
98 QString caption("Load a mussa parameter file");
99 QString filter("Mussa Parameters (*.mupa)");
100 QString mupa_path = QFileDialog::getOpenFileName(this,
105 if (mupa_path.isNull())
107 // try to load safely
109 Mussa *m = new Mussa;
110 m->load_mupa_file(mupa_path.toStdString());
111 m->analyze(0, 0, Mussa::TransitiveNway, 0.0);
112 // only switch mussas if we loaded without error
113 delete mussaAnalysis;
116 } catch (mussa_load_error e) {
117 QString msg("Unable to load ");
121 QMessageBox::warning(this, "Load Parameter", msg);
123 assert (mussaAnalysis != 0);
126 void PathScene::loadSavedAnalysis()
128 QString caption("Load a previously run analysis");
129 QString muway_dir = QFileDialog::getExistingDirectory(this,
131 QDir::currentPath());
133 if (muway_dir.isNull())
135 // try to safely load
137 Mussa *m = new Mussa;
138 m->load(muway_dir.toStdString());
139 // only switch mussas if we loaded without error
140 delete mussaAnalysis;
143 } catch (mussa_load_error e) {
144 QString msg("Unable to load ");
148 QMessageBox::warning(this, "Load Parameter", msg);
150 assert (mussaAnalysis != 0);
153 void PathScene::setSoftThreshold(int threshold)
155 if (mussaAnalysis->get_threshold() != threshold) {
156 mussaAnalysis->set_soft_thres(threshold);
157 mussaAnalysis->nway();
164 void PathScene::initializeGL()
166 glEnable(GL_DEPTH_TEST);
167 glClearColor(1.0, 1.0, 1.0, 0.0);
168 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
169 glShadeModel(GL_FLAT);
172 void PathScene::resizeGL(int width, int height)
174 viewport_width = width;
175 viewport_height = height;
176 assert (geometry().width() == width);
177 assert (geometry().height() == height);
178 glViewport(0, 0, (GLsizei)width, (GLsizei)height);
179 glMatrixMode(GL_PROJECTION);
181 // I'm abusing this as Qt and OpenGL disagree about the direction of the
183 glOrtho(curOrtho2d.left(), curOrtho2d.right(),
184 curOrtho2d.top(), curOrtho2d.bottom(),
188 void PathScene::paintGL()
190 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
193 glMatrixMode(GL_PROJECTION);
195 glOrtho(curOrtho2d.left(), curOrtho2d.right(),
196 curOrtho2d.top(), curOrtho2d.bottom(),
198 glMatrixMode(GL_MODELVIEW);
201 glDepthMask(GL_FALSE);
202 if (selectedMode && !drawingBand) {
203 glColor4f(0.4, 0.4, 0.4, 0.9);
204 glRectf(previousBand.x(), previousBand.y(),
205 previousBand.right(), previousBand.bottom());
206 cout << "x: " << previousBand.x() << " r:" << previousBand.right() << endl;
208 glDepthMask(GL_TRUE);
214 void PathScene::updateScene()
216 // Delete old glsequences
217 // FIXME: does this actually free the memory from the new'ed GlSequences?
220 // save a reference to our GlSequences
222 float y = mussaAnalysis->sequences().size() * 100 ;
223 float max_base_pairs = 0;
224 typedef vector<Sequence>::const_iterator seqs_itor_t;
225 for(seqs_itor_t seq_itor = mussaAnalysis->sequences().begin();
226 seq_itor != mussaAnalysis->sequences().end();
230 gl_seq = new GlSequence(*seq_itor);
233 if (gl_seq->width() > max_base_pairs ) max_base_pairs = gl_seq->width();
234 tracks.push_back( *gl_seq );
236 maxOrtho2d.setWidth(max_base_pairs + 100.0);
237 maxOrtho2d.setHeight((mussaAnalysis->sequences().size()) * 100 );
238 curOrtho2d = maxOrtho2d;
241 void PathScene::processSelection(GLuint hits, GLuint buffer[], GLuint bufsize)
243 const size_t pathz_count = mussaAnalysis->paths().refined_pathz.size();
251 selectedPaths.clear();
252 selectedPaths.reserve(pathz_count);
253 selectedPaths.insert(selectedPaths.begin(), pathz_count, false);
254 selectedTrack = 0x7fffffff;
256 std::cout << "hits = " << hits << " " << pathz_count << std::endl;
257 ptr = (GLuint *) buffer;
260 for (GLuint i=0; i < hits; ++i)
262 if ((i + 5) > bufsize) {
263 std::clog << "*** selection overflow***" << std::endl;
266 z1 = ((float)*ptr++)/0x7fffffff;
267 z2 = ((float)*ptr++)/0x7fffffff;
271 std::clog << "wrong number of glNames, selection is having trouble ";
272 std::clog << " got " << names << std::endl;
273 std::clog << " names: " ;
274 for (GLuint j = 0 ; j < names-2; ++j) {
275 std::clog << *ptr++ << " ";
282 selectedPaths[objid] = true;
285 if (objid < selectedTrack) {
286 selectedTrack = objid;
294 void PathScene::mousePressEvent( QMouseEvent *e)
297 std::cout << "x=" << e->x() << " y=" << e->y() << std::endl;
299 selectedMode = false;
300 bandOrigin = e->pos();
302 rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
304 rubberBand->setGeometry(QRect(bandOrigin, QSize()));
308 void PathScene::mouseMoveEvent( QMouseEvent *e)
310 rubberBand->setGeometry(QRect(bandOrigin, e->pos()).normalized());
313 void dumpRect(const QRect &r)
315 std::cout << "x=" << r.x() << " y=" << r.y()
316 << " w=" << r.width() << " h=" << r.height() << std::endl;
319 void PathScene::mouseReleaseEvent( QMouseEvent *e)
323 QRect r = QRect(bandOrigin, e->pos()).normalized();
324 bandOrigin = r.topLeft();
325 std::cout << "band ";
328 std::cout << "window ";
329 dumpRect(geometry());
331 GLfloat x_scale = curOrtho2d.width()/((float)geometry().width());
332 GLfloat y_scale = curOrtho2d.height()/((float)geometry().height());
333 GLfloat x_left = curOrtho2d.left() + (r.x()*x_scale);
334 GLfloat x_right = x_left + r.width() * x_scale;
335 // using QRectF with Y axis swapped
336 GLfloat y_top = curOrtho2d.bottom()-(r.y()*y_scale);
337 GLfloat y_bottom = y_top - r.height() * y_scale;
338 previousBand.setCoords(x_left, y_top, x_right, y_bottom);
339 std::cout << x_left << " " << x_right << " " << y_top << " " << y_bottom
342 // hopefully this will make a buffer big enough to receive
343 // everything being selected
344 const size_t pathz_count = mussaAnalysis->paths().refined_pathz.size();
345 const GLuint select_buf_size = 1 + 5 * (pathz_count + tracks.size()) ;
346 GLuint selectBuf[select_buf_size];
347 glSelectBuffer(select_buf_size, selectBuf);
350 (void)glRenderMode(GL_SELECT);
352 glMatrixMode(GL_PROJECTION);
354 glOrtho(x_left, x_right, y_top, y_bottom, -50.0, 50.0);
355 glMatrixMode(GL_MODELVIEW);
362 hits = glRenderMode(GL_RENDER);
363 processSelection(hits, selectBuf, select_buf_size);
365 resizeGL(geometry().width(), geometry().height());
370 // openGl rendering code
372 void PathScene::draw_tracks() const
376 for (vector<GlSequence>::size_type i = 0; i != tracks.size(); ++i )
379 tracks[i].draw(curOrtho2d.left(), curOrtho2d.right());
385 void PathScene::draw_lines() const
391 bool reversed = false;
392 bool prevReversed = false;
393 const NwayPaths& nway = mussaAnalysis->paths();
397 vector<GlSequence>::const_iterator track_itor;
399 typedef list<ExtendedConservedPath> conserved_paths;
400 typedef conserved_paths::const_iterator const_conserved_paths_itor;
401 for(const_conserved_paths_itor path_itor = nway.refined_pathz.begin();
402 path_itor != nway.refined_pathz.end();
403 ++path_itor, ++objid)
405 track_itor = tracks.begin();
406 // since we were drawing to the start of a window, and opengl lines
407 // are centered around the two connecting points our lines were slightly
408 // offset. the idea of window_offset is to adjust them to the
409 // right for forward compliment or left for reverse compliment
410 // FIXME: figure out how to unit test these computations
411 GLfloat window_offset = (path_itor->window_size)/2.0;
413 glBegin(GL_LINE_STRIP);
414 for (vector<int>::const_iterator sp_itor = path_itor->begin();
415 sp_itor != path_itor->end();
416 ++sp_itor, ++track_itor)
420 // at some point when we modify the pathz data structure to keep
421 // track of the score we can put grab the depth here.
423 // are we reverse complimented?
428 x = -x; // make positive
431 x += window_offset; // move right for forward compliment
433 x -= window_offset; // move left for reverse compliment
434 // the following boolean implements logical xor
435 if ( (reversed || prevReversed) && (!reversed || !prevReversed)) {
436 // we have a different orientation
437 if (not selectedMode or selectedPaths[objid] == true) {
438 // if we have nothing selected, or we're the highlight, be bright
439 glColor3f(0.0, 0.0, 1.0);
442 glColor3f(0.5, 0.5, 1.0);
445 // both current and previous path have the same orientation
446 if (not selectedMode or selectedPaths[objid] == true) {
447 glColor3f(1.0, 0.0, 0.2);
449 glColor3f(1.0, 0.5, 0.5);
452 prevReversed = reversed;
453 glVertex3f(x, y, 0.0);
456 glLoadName(++pathid);
461 GLuint PathScene::make_line_list()
463 GLuint line_list = glGenLists(1);
464 glNewList(line_list, GL_COMPILE);
473 void PathScene::mussaesque()
475 //static GLuint theLines = make_line_list();
478 glPushName(MussaPaths);
479 //glCallList(theLines);
481 glLoadName(MussaTracks);