1 #include "alg/glseqbrowser.hpp"
2 #include "mussa_exceptions.hpp"
9 GlSeqBrowser::GlSeqBrowser()
11 cur_ortho(400.0, 0.0, 600.0, 0.0),
12 viewport_size(600, 400),
13 viewport_center((cur_ortho.right-cur_ortho.left)/2+cur_ortho.left),
20 GlSeqBrowser::GlSeqBrowser(const GlSeqBrowser& gt)
21 : border_width(gt.border_width),
22 cur_ortho(gt.cur_ortho),
23 viewport_size(gt.viewport_size),
24 viewport_center(gt.viewport_center),
25 zoom_level(gt.zoom_level),
26 color_mapper(gt.color_mapper),
27 track_container(gt.track_container)
31 void GlSeqBrowser::initializeGL()
33 glEnable(GL_DEPTH_TEST);
34 glClearColor(1.0, 1.0, 1.0, 0.0);
35 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
36 glShadeModel(GL_FLAT);
39 void GlSeqBrowser::resizeGL(int width, int height)
41 viewport_size.x = width;
42 viewport_size.y = height;
43 glViewport(0, 0, (GLsizei)width, (GLsizei)height);
44 update_viewport(viewport_center, zoom_level);
47 void GlSeqBrowser::paintGL() const
49 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
52 glMatrixMode(GL_PROJECTION);
54 glOrtho(cur_ortho.left, cur_ortho.right,
55 cur_ortho.bottom, cur_ortho.top,
64 void GlSeqBrowser::processSelection(GLuint hits, GLuint buffer[], GLuint bufsize)
68 GLuint consumed_names = 0;
73 GLuint path_index = 0;
74 GLuint pair_key_0 = 0;
75 GLuint pair_key_1 = 0;
77 selected_paths.clear();
78 selected_tracks.clear();
80 std::cout << "hits = " << hits << std::endl;
81 ptr = (GLuint *) buffer;
84 for (GLuint i=0; i < hits; ++i)
86 if ((i + 5) > bufsize) {
87 std::clog << "*** selection overflow***" << std::endl;
91 z1 = ((float)*ptr++)/0x7fffffff;
92 z2 = ((float)*ptr++)/0x7fffffff;
93 objtype = *ptr++; ++consumed_names;
96 path_index = *ptr++; ++consumed_names;
97 pair_key_0 = *ptr++; ++consumed_names;
98 pair_key_1 = *ptr++; ++consumed_names;
99 if (path_index < path_segments.size()) {
100 segment_key k(pair_key_0, pair_key_1);
101 pair_segment_map::iterator psm_i;
102 psm_i = path_segments[path_index].find(k);
103 if (psm_i != path_segments[path_index].end()) {
104 Segment &seg = psm_i->second;
105 selected_paths.insert(seg.path_ids.begin(), seg.path_ids.end());
107 // else something else is wrong
109 // something wasn't right
110 clog << "invalid path_index " << path_index
111 << " should have been [0,"<<path_segments.size()
116 objid = *ptr++; ++consumed_names;
117 selected_tracks.insert(objid);
120 cout << "unknown type " << objtype << " ";
121 for(; consumed_names < names; ++consumed_names) {
122 cout << consumed_names << "," << *ptr++ << " ";
131 void GlSeqBrowser::selectRegion(int top, int left, int bottom, int right)
133 GLfloat x_scale = cur_ortho.width()/((float)viewport_size.x);
134 GLfloat y_scale = cur_ortho.height()/((float)viewport_size.y);
135 GLfloat x_left = cur_ortho.left + (left*x_scale);
136 GLfloat x_right = right * x_scale;
139 // woah, someone gave us a rectangle with the origin in the lower left
144 // swap the orientation of canvas coordinates
145 GLfloat y_top = cur_ortho.top-(bottom*y_scale);
146 GLfloat y_bottom = cur_ortho.top - top * y_scale;
147 selectedRegion = rect<float>(y_top, x_left, y_bottom, x_right);
149 // hopefully this will make a buffer big enough to receive
150 // everything being selected
151 //const size_t pathz_count = mussaAnalysis->paths().refined_pathz.size();
152 //const GLuint select_buf_size = 1 + 5 * (pathz_count + sequences.size());
153 const GLuint select_buf_size = 500000;
154 GLuint selectBuf[select_buf_size];
155 glSelectBuffer(select_buf_size, selectBuf);
158 (void)glRenderMode(GL_SELECT);
160 glMatrixMode(GL_PROJECTION);
162 glOrtho(x_left, x_right, y_top, y_bottom, -50.0, 50.0);
163 glMatrixMode(GL_MODELVIEW);
170 hits = glRenderMode(GL_RENDER);
171 processSelection(hits, selectBuf, select_buf_size);
174 float GlSeqBrowser::border() const
179 float GlSeqBrowser::left() const
182 if (track_container.size() == 0)
184 return cur_ortho.left;
186 vector<GlSequence>::const_iterator track_i = track_container.begin();
188 for( ; track_i != track_container.end(); ++track_i)
190 if (track_i->x() < left) {
194 return left-border_width;
198 float GlSeqBrowser::right() const
201 if (track_container.size() == 0) {
202 return cur_ortho.right;
204 vector<GlSequence>::const_iterator track_i = track_container.begin();
205 right = track_i->right();
206 for( ; track_i != track_container.end(); ++track_i) {
207 if (track_i->right() > right)
208 right = track_i->right();
210 return right+border_width;
214 void GlSeqBrowser::setViewportCenter(float x)
216 update_viewport(x, zoom_level);
220 float GlSeqBrowser::viewportLeft() const
222 return cur_ortho.left;
225 float GlSeqBrowser::viewportCenter() const
227 return viewport_center;
230 float GlSeqBrowser::viewportRight() const
232 return cur_ortho.right;
235 float GlSeqBrowser::viewportHeight() const
237 return cur_ortho.top - cur_ortho.bottom;
240 float GlSeqBrowser::viewportWidth() const
242 return cur_ortho.right - cur_ortho.left;
245 int GlSeqBrowser::zoomOut()
248 if (right() - left() > 0) {
249 cur_ortho.left = left();
250 cur_ortho.right = right();
251 zoom_level = (int)(( (right() - left()) / viewport_size.x) * 100);
254 // made up number representing 50 bp / pixel
258 int GlSeqBrowser::zoomToSequence()
260 // (experimentally determined zoom level)
261 const int friendly_zoom = 7;
262 setZoom(friendly_zoom);
263 return friendly_zoom;
265 void GlSeqBrowser::setZoom(int new_zoom)
267 update_viewport(viewport_center, new_zoom);
268 zoom_level = new_zoom;
271 int GlSeqBrowser::zoom() const
276 void GlSeqBrowser::setColorMapper(AnnotationColors& cm)
281 AnnotationColors& GlSeqBrowser::colorMapper()
286 void GlSeqBrowser::clear()
289 path_segments.clear();
290 track_container.clear();
293 void GlSeqBrowser::push_sequence(const Sequence &s)
295 GlSequence gs(s, color_mapper);
299 void GlSeqBrowser::push_sequence(GlSequence &gs)
303 track_container.push_back(gs);
305 if (track_container.size() > 1)
306 path_segments.push_back(pair_segment_map());
309 const std::vector<GlSequence>& GlSeqBrowser::sequences() const
311 return track_container;
314 void GlSeqBrowser::clear_links()
316 path_segments.clear();
317 for (int i = track_container.size()-1; i > 0; --i)
319 path_segments.push_back(pair_segment_map());
324 GlSeqBrowser::link(const vector<int>& path, const vector<bool>& rc, int )
326 if (path.size() < 2) {
327 // should i throw an error instead?
330 if (path.size() != rc.size()) {
331 throw runtime_error("path and reverse compliment must be the same length");
333 vector<int>::const_iterator path_i = path.begin();
334 vector<bool>::const_iterator rc_i = rc.begin();
336 int prev_x = *path_i; ++path_i;
337 bool prev_rc = *rc_i; ++rc_i;
338 while (path_i != path.end() and rc_i != rc.end())
340 segment_key p(prev_x, *path_i);
341 pair_segment_map::iterator found_segment = path_segments[track_i].find(p);
342 if (found_segment == path_segments[track_i].end()) {
344 float y1 = track_container[track_i].y();
345 y1 -= track_container[track_i].height()/2;
346 float y2 = track_container[track_i+1].y();
347 y2 += track_container[track_i+1].height()/2;
349 Segment s(prev_x, y1, *path_i, y2, prev_rc);
350 s.path_ids.insert(pathid);
351 path_segments[track_i][p] = s;
354 found_segment->second.path_ids.insert(pathid);
362 // pathid is reset by push_sequence
366 const set<int>& GlSeqBrowser::selectedPaths() const
368 return selected_paths;
371 void GlSeqBrowser::centerOnPath(const vector<int>& paths)
373 if (paths.size() != track_container.size()) {
374 throw mussa_error("Path length didn't match the number of sequences");
377 for(size_t track_i = 0; track_i != track_container.size(); ++track_i)
379 // -15 = shift more to the left
380 track_container[track_i].setX((viewport_center-15) - paths[track_i]);
384 void GlSeqBrowser::update_viewport(float center, int new_zoom)
386 // limit how close we can get
390 float new_width = (((float)new_zoom / 100.0) * (float)viewport_size.x);
391 cur_ortho.left = center-new_width/2.0;
392 cur_ortho.right = center+new_width/2.0;
395 void GlSeqBrowser::update_layout()
397 typedef std::vector<GlSequence>::iterator glseq_itor_type;
398 float available_height = (float)cur_ortho.top - 2 * (float)border_width;
399 float max_base_pairs = 0;
400 size_t track_count = track_container.size();
402 if (track_count > 1) {
403 // we have several sequences
404 float track_spacing = available_height / (track_count-1);
405 float y = available_height + (float)border_width;
406 for(glseq_itor_type seq_i = track_container.begin();
407 seq_i != track_container.end();
408 ++seq_i, y-=track_spacing)
412 if (seq_i->length() > max_base_pairs)
413 max_base_pairs = seq_i->length();
415 } else if (track_count == 1) {
416 // center the single track
417 glseq_itor_type seq_i = track_container.begin();
419 seq_i->setY(viewport_size.x /2);
420 max_base_pairs = seq_i->length();
422 // nothing to do as we're empty
425 cur_ortho.right = max_base_pairs + border_width;
426 cur_ortho.left = -border_width;
427 cur_ortho.top = viewport_size.x;
428 cur_ortho.bottom = 0;
429 viewport_center = (cur_ortho.width()/2) + cur_ortho.left;
433 void GlSeqBrowser::draw() const
435 glMatrixMode(GL_MODELVIEW);
437 glPushName(MussaSegment);
439 glLoadName(MussaTrack);
442 // a selection shouldn't have a glName associated with it
446 void GlSeqBrowser::draw_selection() const
448 // draw selection box
450 glDepthMask(GL_FALSE);
452 glColor4f(0.6, 0.6, 0.6, 0.9);
453 glRectf(selectedRegion.left, selectedRegion.top,
454 selectedRegion.right, selectedRegion.bottom);
456 glDepthMask(GL_TRUE);
460 void GlSeqBrowser::draw_tracks() const
462 for(size_t track_i = 0; track_i != track_container.size(); ++track_i)
465 track_container[track_i].draw(cur_ortho.left, cur_ortho.right);
470 void GlSeqBrowser::draw_segments() const
473 // each vector contains path_segment_maps of all the connections
474 // between this track and the next
475 path_segment_map_vector::const_iterator psmv_i;
476 for(psmv_i = path_segments.begin();
477 psmv_i != path_segments.end();
480 path_segment_map_vector::difference_type path_index;
481 path_index = psmv_i - path_segments.begin();
482 // these maps contain the pair index (used so we dont keep drawing the
483 // same segment) and the actual segment structure.
484 pair_segment_map::const_iterator psm_i;
485 for(psm_i = psmv_i->begin();
486 psm_i != psmv_i->end();
489 // grab the index into our segment map
490 const segment_key& key = psm_i->first;
491 // the second element of our map pair is a segment
492 const Segment &s = psm_i->second;
493 // need to do something so we can detect our selection
494 vector<int> selected;
495 set_intersection(selected_paths.begin(), selected_paths.end(),
496 s.path_ids.begin(), s.path_ids.end(),
497 back_inserter(selected));
499 if (not s.reversed) {
500 if (selected_paths.size() == 0 or selected.size() > 0) {
501 glColor3f(1.0, 0.0, 0.0);
503 glColor3f(1.0, 0.8, 0.8);
506 if (selected_paths.size() == 0 or selected.size() > 0) {
507 glColor3f(0.0, 0.0, 1.0);
509 glColor3f(0.8, 0.8, 1.0);
512 // save the multipart name for our segment
513 glPushName(path_index); glPushName(key.first); glPushName(key.second);
515 float seq_start_x = track_container[path_index].x();
516 float seq_end_x = track_container[path_index+1].x();
517 glVertex3f(s.start.x + seq_start_x, s.start.y, -1);
518 glVertex3f(s.end.x + seq_end_x , s.end.y, -1);
521 glPopName(); glPopName(); glPopName();