Store Sequence sequence location in a shared_ptr class
[mussa.git] / alg / glsequence.cpp
index fecb29f75c89d7978ba36445cafbe938a6b9ea95..73fc4daaeeac20b95fe27769ca2c613748cd0534 100644 (file)
@@ -6,20 +6,21 @@
 #include <stdexcept>
 using namespace std;
 
-GlSequence::GlSequence(const Sequence &s, AnnotationColors& cm) 
-  : seq(s),
+GlSequence::GlSequence(const Sequence &s, 
+                       boost::shared_ptr<AnnotationColors> cm) 
+  : Sequence(s),
     seq_x(0.0), 
     seq_y(0.0), 
     seq_z(1.0), 
     seq_height(12.0),
     color_mapper(cm),
-    drawColor(0.0, 0.0, 0.0),
-    char_pix_per_world_unit(5.0)
+    drawColor(new Color(0.0, 0.0, 0.0)),
+    char_pix_per_world_unit(2.5)
 {
 }
 
 GlSequence::GlSequence(const GlSequence &s)
-  : seq(s.seq),
+  : Sequence(s),
     seq_x(s.seq_x),
     seq_y(s.seq_y),
     seq_z(s.seq_z),
@@ -30,10 +31,22 @@ GlSequence::GlSequence(const GlSequence &s)
 {
 }
 
+GlSequence::GlSequence(const GlSequence *s)
+  : Sequence(s),
+    seq_x(s->seq_x),
+    seq_y(s->seq_y),
+    seq_z(s->seq_z),
+    seq_height(s->seq_height),
+    color_mapper(s->color_mapper),
+    drawColor(s->drawColor),
+    char_pix_per_world_unit(s->char_pix_per_world_unit)
+{
+}
+
 GlSequence &GlSequence::operator=(const GlSequence & s)
 {
   if (this != &s) {
-    const_cast<Sequence &>(seq) = s.seq;
+    Sequence::operator=(s);
     seq_x = s.seq_x;
     seq_y = s.seq_y;
     seq_z = s.seq_z;
@@ -45,11 +58,6 @@ GlSequence &GlSequence::operator=(const GlSequence & s)
   return *this;
 }
 
-const Sequence& GlSequence::sequence() const
-{
-  return seq;
-}
-
 void GlSequence::setX(GLfloat value)
 {
   seq_x = value;
@@ -62,7 +70,7 @@ GLfloat GlSequence::x() const
 
 GLfloat GlSequence::right() const
 {
-  return length()+seq_x;
+  return size()+seq_x;
 }
 
 void GlSequence::setY(GLfloat value)
@@ -80,9 +88,9 @@ GLfloat GlSequence::height() const
   return seq_height;
 }
 
-GLfloat GlSequence::length() const
+GLfloat GlSequence::size() const
 {
-  return seq.size();
+  return Sequence::size();
 }
 
 Sequence::size_type GlSequence::leftbase(GLfloat left) const
@@ -90,8 +98,8 @@ Sequence::size_type GlSequence::leftbase(GLfloat left) const
   left = ceil(left - seq_x);
   if (left < 0)
     return 0;
-  else if (left > seq.size() )
-    return seq.size();
+  else if (left > Sequence::size() )
+    return Sequence::size();
   else
     return (Sequence::size_type)left;
 }
@@ -99,71 +107,80 @@ Sequence::size_type GlSequence::leftbase(GLfloat left) const
 Sequence::size_type GlSequence::rightbase(GLfloat right) const
 {
   right = floor(right) - seq_x;
-  if (right > seq.size())
-    return seq.size();
+  if (right > Sequence::size())
+    return Sequence::size();
   else if ( right < 0) 
     return 0;
   else 
     return (Sequence::size_type)right;
 }
 
-Sequence::const_iterator GlSequence::sequence_begin() const
-{
-  return seq.begin();
-}
-
-Sequence::const_iterator GlSequence::sequence_end() const
-{
-  return seq.end();
-}
-
 Sequence::const_iterator 
-GlSequence::sequence_begin(GLfloat left, GLfloat right) const
+GlSequence::region_begin(GLfloat left, GLfloat right) const
 {
-  if ( leftbase(left) > seq.size() or left > right )
-    return seq.end();
+  if ( leftbase(left) > Sequence::size() or left > right )
+    return Sequence::end();
   else
-    return seq.begin() + leftbase(left);
+    return Sequence::begin() + leftbase(left);
 }
 
 Sequence::const_iterator 
-GlSequence::sequence_end(GLfloat left, GLfloat right) const
+GlSequence::region_end(GLfloat left, GLfloat right) const
 {
-  if ( rightbase(right) > seq.size() or left > right )
-    return seq.end();
+  if ( rightbase(right) > Sequence::size() or left > right )
+    return Sequence::end();
   else
-    return seq.begin() + rightbase(right); 
+    return Sequence::begin() + rightbase(right); 
 }
 
+GlSequence GlSequence::subseq(size_type start, size_type count) const
+{
+  GlSequence new_seq(*this);
+  new_seq.seq = seq->subseq(start, count);
+  copy_children(new_seq, start, count);
+  
+  return new_seq;
+}
 
 //! set default track draw color 
-void GlSequence::setColor(Color &c)
+void GlSequence::setColor(boost::shared_ptr<Color> &c)
 {
   drawColor = c;
 }
 
 //! get default track draw color
-Color GlSequence::color()
+boost::shared_ptr<Color> GlSequence::color()
 {
   return drawColor;
 }
 
-
-int GlSequence::get_viewport_pixel_width()
+int GlSequence::get_viewport_width_in_pixels()
 {
   GLint viewport[4];
   glGetIntegerv(GL_VIEWPORT, viewport);
   return viewport[3]; // grab the viewport width
 }
 
+GLfloat GlSequence::pixelWidth(GLfloat left, GLfloat right) const
+{
+  return pixelWidth(left, right, get_viewport_width_in_pixels());
+}
+
+GLfloat
+GlSequence::pixelWidth(GLfloat left, GLfloat right, int vp_width) const
+{
+  return round((right-left)/vp_width);
+}
+
+bool GlSequence::is_sequence_renderable(GLfloat left, GLfloat right) const
+{
+  return is_sequence_renderable(left, right, get_viewport_width_in_pixels());
+}
+
 bool GlSequence::is_sequence_renderable(GLfloat left, 
                                         GLfloat right, 
                                         int viewport_width) const
 {
-  // if called with default argument, go get the viewable width
-  if (viewport_width == -1) {
-    viewport_width = get_viewport_pixel_width();
-  }
   GLfloat world_width = right - left;
   GLfloat pixels_needed = (char_pix_per_world_unit * world_width);
 
@@ -184,13 +201,19 @@ void GlSequence::draw(GLfloat left, GLfloat right) const
   draw_annotations(left, right);
 }
 
-void GlSequence::draw_box(GLfloat left, GLfloat right, 
+void GlSequence::draw_box(GLfloat world_left, GLfloat world_right,
+                          GLfloat left, GLfloat right, 
                           GLfloat height, GLfloat z) const
 {
+  GLfloat pixel_width = pixelWidth(world_left, world_right);
   GLfloat offset = height/2.0;
   GLfloat top = seq_y + offset;
   GLfloat bottom = seq_y - offset;
-    
+  
+  // make our box be at least 1 pixel
+  if ((right-left) < pixel_width) {
+    right = left + pixel_width;
+  }
   glBegin(GL_QUADS);
     glVertex3f(left,  top,    z);
     glVertex3f(left,  bottom, z);
@@ -201,37 +224,38 @@ void GlSequence::draw_box(GLfloat left, GLfloat right,
 
 void GlSequence::draw_track(GLfloat left, GLfloat right) const
 {
-  glColor3fv(drawColor.get());
+  glColor3fv(drawColor->get());
   // draw main sequence track
-  draw_box(seq_x, seq_x+seq.size(), seq_height, 0.0);
+  draw_box(left, right, seq_x, seq_x+Sequence::size(), seq_height, 0.0);
 }
 
 void GlSequence::draw_annotations(GLfloat left, GLfloat right) const
 {
   // draw annotations
-  GLfloat annotation_z = seq_z + 1.0;
-  const std::list<annot>& annots = seq.annotations();
-  const std::list<motif>& motifs = seq.motifs();
+  GLfloat annotation_z = seq_z + 10.0;
+  const std::list<annot>& annots = Sequence::annotations();
+  const std::list<motif>& motifs = Sequence::motifs();
   for (std::list<annot>::const_iterator annot_itor = annots.begin();
        annot_itor != annots.end();
-       ++annot_itor, ++annotation_z)
+       ++annot_itor)
   {
-    glColor3f(0.0, 0.5, 0.0);
-    draw_box(seq_x+annot_itor->start, seq_x+annot_itor->end, 
+    glColor3f(0.0, 0.8, 0.0);
+    draw_box(left, right, seq_x+annot_itor->begin, seq_x+annot_itor->end, 
              seq_height, annotation_z);
   }
   // if motifs?
   for (std::list<motif>::const_iterator motifs_itor = motifs.begin();
        motifs_itor != motifs.end();
-       ++motifs_itor, ++annotation_z)
+       ++motifs_itor)
   {
-    glColor3fv(color_mapper.lookup("motif", motifs_itor->sequence).get());
-    draw_box(seq_x+motifs_itor->start, seq_x+motifs_itor->end, 
-             seq_height, annotation_z);
+    glColor3fv(color_mapper->lookup("motif", motifs_itor->sequence).get());
+    draw_box(left, right, seq_x+motifs_itor->begin, seq_x+motifs_itor->end, 
+             seq_height, annotation_z+1.0);
   }
 
 }
 
+// this way of drawing characters, came from the red open gl book
 const int PT = 1;
 const int STROKE = 2;
 const int END =3;
@@ -264,6 +288,9 @@ CP Cdata[] = {
 CP Xdata[] = {{ 0, 5, PT}, {5, -5,STROKE},{0,-5,PT},{5, 5, END}};
 CP Ndata[] = {{ 0, -5, PT}, {0, 5, PT}, {5, -5, PT}, {5, 5, END}};
 
+//! the maximum width used for a charcter glyph
+const int max_glyph_width = 5; // unit ( glyph_coord )
+
 static void drawLetter(CP *l, GLfloat z)
 {
   glBegin(GL_LINE_STRIP);
@@ -294,19 +321,24 @@ void GlSequence::draw_sequence(GLfloat left, GLfloat right) const
   // FIXME: basically this needs to be greater than the number of annotations
   const GLfloat z = 30;
   glLineWidth(1);
-  glColor3fv(drawColor.get());
+  glColor3fv(drawColor->get());
 
-  Sequence::const_iterator seq_itor = sequence_begin(left, right);
-  Sequence::const_iterator seq_end = sequence_end(left, right);
+  Sequence::const_iterator seq_itor = region_begin(left, right);
+  Sequence::const_iterator seq_end = region_end(left, right);
   Sequence::size_type basepair = 0;
+  const float bp_per_world = 1.0; //( world coord )
+  const float glyph_x_scale = 0.125; // unit = ( world coord / glyph coord )
+  // compute how much space there should be to either size of a letter
+  const float glyph_margin = (bp_per_world - glyph_x_scale * max_glyph_width) 
+                           / 2.0;  
 
   assert(seq_end - seq_itor >= 0);
   while(seq_itor != seq_end)
   {
-    assert ( basepair < seq.size() );
+    assert ( basepair < Sequence::size() );
     glPushMatrix();
-    glTranslatef( seq_x+leftbase(left) + basepair, seq_y, 1.0 );
-    glScalef(0.1, 1.0, 1.0);
+    glTranslatef( seq_x+leftbase(left) + basepair + glyph_margin, seq_y, 1.0 );
+    glScalef(glyph_x_scale, 1.0, 1.0);
     switch (*seq_itor) {
       case 'A': case 'a':
         drawLetter(Adata, z);