1 #include "alg/glsequence.hpp"
9 static const float default_height = 12.0;
11 GlSequence::GlSequence(const Sequence &s,
12 boost::shared_ptr<AnnotationColors> cm)
15 char_pix_per_world_unit(2.5)
17 seq->setDrawable(default_drawable());
20 GlSequence::GlSequence(const GlSequence &s)
22 color_mapper(s.color_mapper),
23 char_pix_per_world_unit(s.char_pix_per_world_unit)
25 seq->setDrawable(copy_drawable(s.seq->drawable()));
28 GlSequence::GlSequence(const GlSequence *s)
30 color_mapper(s->color_mapper),
31 char_pix_per_world_unit(s->char_pix_per_world_unit)
33 seq->setDrawable(copy_drawable(s->seq->drawable()));
36 GlSequence::GlSequence(const GlSequenceRef s)
37 : Sequence( (SequenceRef)s ),
38 color_mapper(s->color_mapper),
39 char_pix_per_world_unit(s->char_pix_per_world_unit)
41 seq->setDrawable(copy_drawable(s->seq->drawable()));
44 GlSequence &GlSequence::operator=(const GlSequence & s)
47 Sequence::operator=(s);
48 seq->setDrawable(copy_drawable(s.seq->drawable()));
49 color_mapper = s.color_mapper;
50 assert(char_pix_per_world_unit == s.char_pix_per_world_unit);
55 DrawableRef GlSequence::default_drawable()
57 ColorRef c(new Color(0.0, 0.0, 0.0));
58 DrawableRef d(new Drawable(0.0, 0.0, 1.0, default_height, c));
62 DrawableRef GlSequence::copy_drawable(DrawableRef old_d)
64 ColorRef c(old_d->color());
65 DrawableRef d(new Drawable(old_d));
71 SeqSpanRef GlSequence::make_undefined_sequence_annotation(
72 Drawable::draw_func_ptr draw,
76 // create all the components of our annotation
77 // (should seq_i-start_i
78 SeqSpanRef empty_seq(seq->subseq(start, count));
79 AnnotationsRef empty_seq_annot(new Annotations("null"));
80 DrawableRef drawable(default_drawable());
81 // glue everything to gether
82 drawable->setDrawFunction(draw);
83 empty_seq->setAnnotations(empty_seq_annot);
84 empty_seq->setDrawable(drawable);
88 void GlSequence::add_annotations_for_undefined_sequence(Drawable::draw_func_ptr draw)
90 Sequence::const_iterator start_i = begin();
91 Sequence::const_iterator seq_i = begin();
92 Sequence::const_iterator end_i = end();
94 Sequence::const_iterator start_block_i = end();
95 for(; seq_i != end_i; ++seq_i)
97 // need a better set of characters to serch for
98 if (*seq_i == 'N' or *seq_i == 'n') {
99 if (start_block_i == end_i) {
100 start_block_i = seq_i;
103 if (start_block_i != end_i) {
105 size_type start = start_block_i - start_i;
106 size_type count = seq_i - start_block_i;
107 // add the annotation
108 add_annotation(make_undefined_sequence_annotation(draw, start, count));
109 // reset our counter...
110 start_block_i = end_i;
114 // catch stuff at the end
115 if( start_block_i != end_i ) {
116 size_type start = start_block_i - start_i;
117 size_type count = seq_i - start_block_i;
118 add_annotation(make_undefined_sequence_annotation(draw, start, count));
123 void GlSequence::setX(float value)
125 seq->drawable()->setX(value);
128 float GlSequence::x() const
130 return seq->drawable()->x();
133 void GlSequence::setY(GLfloat value)
135 seq->drawable()->setY(value);
138 float GlSequence::y() const
140 return seq->drawable()->y();
143 float GlSequence::z() const
145 return seq->drawable()->z();
148 float GlSequence::height() const
150 return seq->drawable()->height();
153 GLfloat GlSequence::right() const
158 GLfloat GlSequence::size() const
160 return Sequence::size();
163 Sequence::size_type GlSequence::leftbase(GLfloat left) const
165 left = ceil(left - x());
168 else if (left > Sequence::size() )
169 return Sequence::size();
171 return (Sequence::size_type)left;
174 Sequence::size_type GlSequence::rightbase(GLfloat right) const
176 right = floor(right) - x();
177 if (right > Sequence::size())
178 return Sequence::size();
182 return (Sequence::size_type)right;
185 Sequence::const_iterator
186 GlSequence::region_begin(GLfloat left, GLfloat right) const
188 if ( leftbase(left) > Sequence::size() or left > right )
189 return Sequence::end();
191 return Sequence::begin() + leftbase(left);
194 Sequence::const_iterator
195 GlSequence::region_end(GLfloat left, GLfloat right) const
197 if ( rightbase(right) > Sequence::size() or left > right )
198 return Sequence::end();
200 return Sequence::begin() + rightbase(right);
203 GlSequence GlSequence::subseq(size_type start, size_type count) const
205 GlSequence new_seq(*this);
206 new_seq.seq = seq->subseq(start, count);
207 // make sure our subseq has a drawable attached to it
208 // perhaps we should figure out correct x,y,z,h coords
209 DrawableRef d(default_drawable());
210 // and default to our current color
213 new_seq.seq->setDrawable(d);
214 copy_children(new_seq, start, count);
219 void GlSequence::setColor(ColorRef &c)
221 seq->drawable()->setColor(c);
224 ColorRef GlSequence::color()
226 return seq->drawable()->color();
229 const ColorRef GlSequence::color() const
231 return seq->drawable()->color();
234 int GlSequence::get_viewport_width_in_pixels()
237 glGetIntegerv(GL_VIEWPORT, viewport);
238 return viewport[3]; // grab the viewport width
241 GLfloat GlSequence::pixelWidth(GLfloat left, GLfloat right)
243 return pixelWidth(left, right, get_viewport_width_in_pixels());
247 GlSequence::pixelWidth(GLfloat left, GLfloat right, int vp_width)
249 return round((right-left)/vp_width);
252 bool GlSequence::is_sequence_renderable(GLfloat left, GLfloat right) const
254 return is_sequence_renderable(left, right, get_viewport_width_in_pixels());
257 bool GlSequence::is_sequence_renderable(GLfloat left,
259 int viewport_width) const
261 GLfloat world_width = right - left;
262 GLfloat pixels_needed = (char_pix_per_world_unit * world_width);
264 // if the number of pixels taken up by rendering the characters
265 // that'd show up in the current ortho width is less than the window
266 // width we can actually draw something
267 return pixels_needed < viewport_width;
271 void GlSequence::draw(GLfloat left, GLfloat right) const
273 if ( not is_sequence_renderable(left, right) ) {
274 draw_track(left, right);
276 draw_sequence(left, right);
278 draw_annotations(left, right);
281 void GlSequence::draw_box(GLfloat world_left, GLfloat world_right,
282 GLfloat left, GLfloat right,
283 GLfloat height, GLfloat y, GLfloat z)
285 GLfloat pixel_width = pixelWidth(world_left, world_right);
286 GLfloat offset = height/2.0;
287 GLfloat top = y + offset;
288 GLfloat bottom = y - offset;
290 // make our box be at least 1 pixel
291 if ((right-left) < pixel_width) {
292 right = left + pixel_width;
295 glVertex3f(left, top, z);
296 glVertex3f(left, bottom, z);
297 glVertex3f(right, bottom, z);
298 glVertex3f(right, top, z);
302 void GlSequence::draw_track(GLfloat left, GLfloat right) const
304 glColor3fv(color()->get());
305 // draw main sequence track
306 draw_box(left, right, x(), x()+Sequence::size(), height(), y(), 0.0);
309 void GlSequence::draw_annotations(GLfloat left, GLfloat right) const
312 GLfloat annotation_z = z() + 10.0;
313 const SeqSpanRefList& annots = Sequence::annotations();
314 const MotifList& motifs = Sequence::motifs();
315 for (SeqSpanRefList::const_iterator annot_itor = annots.begin();
316 annot_itor != annots.end();
319 DrawableRef drawable((*annot_itor)->drawable());
320 if (drawable and drawable->drawFunction()) {
321 assert((*annot_itor)->parent() == seq);
322 drawable->drawFunction()((*annot_itor), left, right);
324 glColor3f(0.0, 0.8, 0.0);
325 draw_box(left, right, x()+(*annot_itor)->start(), x()+(*annot_itor)->stop(),
326 height(), y(), annotation_z);
330 for (MotifList::const_iterator motifs_itor = motifs.begin();
331 motifs_itor != motifs.end();
334 glColor3fv(color_mapper->lookup("motif", motifs_itor->sequence).get());
335 draw_box(left, right, x()+motifs_itor->begin, x()+motifs_itor->end,
336 height(), y(), annotation_z+1.0);
340 // this way of drawing characters, came from the red open gl book
342 const int STROKE = 2;
345 typedef struct charpoint {
351 {0, -5, PT}, {2.5, 5, PT}, {5, -5, STROKE},
352 {0.75, -2, PT}, {4.25, -2, END}
356 {2.5, -5, PT}, {2.5,5, STROKE}, {0, 5, PT}, {5, 5, END}
360 {5, 3, PT}, {3, 5, PT}, {2, 5, PT}, {0, 3, PT}, {0, -3, PT},
361 {2, -5, PT}, {3, -5, PT}, {5, -3, STROKE},
362 {2.5, -1, PT}, {5, -1,PT}, {5, -5, END}
366 {4.9, 3, PT}, {3, 5, PT}, {2, 5, PT}, {0, 3, PT}, {0, -3, PT},
367 {2, -5, PT}, {3, -5, PT}, {5, -3, END}
370 CP Xdata[] = {{ 0, 5, PT}, {5, -5,STROKE},{0,-5,PT},{5, 5, END}};
371 CP Ndata[] = {{ 0, -5, PT}, {0, 5, PT}, {5, -5, PT}, {5, 5, END}};
373 //! the maximum width used for a charcter glyph
374 const int max_glyph_width = 5; // unit ( glyph_coord )
376 static void drawLetter(CP *l, GLfloat z)
378 glBegin(GL_LINE_STRIP);
382 glVertex3f(l->x, l->y, z);
385 glVertex3f(l->x, l->y, z);
387 glBegin(GL_LINE_STRIP);
390 glVertex3f(l->x, l->y, z);
395 throw runtime_error("data structure failure");
401 void GlSequence::draw_sequence(GLfloat left, GLfloat right) const
403 // FIXME: basically this needs to be greater than the number of annotations
404 const GLfloat z = 30;
406 glColor3fv(color()->get());
408 Sequence::const_iterator seq_itor = region_begin(left, right);
409 Sequence::const_iterator seq_end = region_end(left, right);
410 Sequence::size_type basepair = 0;
411 const float bp_per_world = 1.0; //( world coord )
412 const float glyph_x_scale = 0.125; // unit = ( world coord / glyph coord )
413 // compute how much space there should be to either size of a letter
414 const float glyph_margin = (bp_per_world - glyph_x_scale * max_glyph_width)
417 assert(seq_end - seq_itor >= 0);
418 while(seq_itor != seq_end)
420 assert ( basepair < Sequence::size() );
422 glTranslatef( x()+leftbase(left) + basepair + glyph_margin, y(), 1.0 );
423 glScalef(glyph_x_scale, 1.0, 1.0);
426 drawLetter(Adata, z);
429 drawLetter(Tdata, z);
432 drawLetter(Gdata, z);
435 drawLetter(Cdata, z);
438 drawLetter(Ndata, z);
441 drawLetter(Xdata, z);
450 bool operator==(const GlSequence &left, const GlSequence &right)
452 return ( (left.x() == right.x()) and
453 (left.y() == right.y()) and
454 (left.z() == right.z()) and
455 (left.height() == right.height()) and
456 (left.color() == right.color()));
459 void draw_narrow_track(SeqSpanRef s, float left, float right)
461 SeqSpanRef parent(s->parent());
462 DrawableRef parent_draw(parent->drawable());
463 float x( (parent_draw) ? parent_draw->x() : 0);
464 float y( (parent_draw) ? parent_draw->y() : 0);
465 float z( (parent_draw) ? parent_draw->z() : 10 );
466 float height( (parent_draw) ? parent_draw->height() : default_height );
468 glColor3f(1.0, 1.0, 1.0);
469 // offset to middle of the top (+) or bottom (-) quarter
470 float yoffset = height * 5.0/8.0; //(1/2 + 1/8)
471 // height of a quarter
472 float hsmall = height * 1.0/4.0;
473 GlSequence::draw_box(left, right, x+s->start(), x+s->stop(),
475 //GlSequence::draw_box(left, right, x+s->start(), x+s->stop(),
476 // hsmall, y-yoffset, z+10);