make the N whiteout a bit bigger
[mussa.git] / alg / glsequence.cpp
index 6cb1b578fc211c59bcd39c68f721b816116c27fc..6c8b12b80410418e2e8bc2c0ec537a574724283a 100644 (file)
 #include <stdexcept>
 using namespace std;
 
-GlSequence::GlSequence(boost::shared_ptr<Sequence> s, 
+static const float default_height = 12.0;
+
+GlSequence::GlSequence(const Sequence &s, 
                        boost::shared_ptr<AnnotationColors> cm) 
-  : seq(s),
-    seq_x(0.0), 
-    seq_y(0.0), 
-    seq_z(1.0), 
-    seq_height(12.0),
+  : Sequence(s),
     color_mapper(cm),
-    drawColor(0.0, 0.0, 0.0),
     char_pix_per_world_unit(2.5)
 {
+  seq->setDrawable(default_drawable());
 }
 
 GlSequence::GlSequence(const GlSequence &s)
-  : seq(s.seq),
-    seq_x(s.seq_x),
-    seq_y(s.seq_y),
-    seq_z(s.seq_z),
-    seq_height(s.seq_height),
+  : Sequence(s),
     color_mapper(s.color_mapper),
-    drawColor(s.drawColor),
     char_pix_per_world_unit(s.char_pix_per_world_unit)
 {
+  seq->setDrawable(copy_drawable(s.seq->drawable()));
+}
+
+GlSequence::GlSequence(const GlSequence *s)
+  : Sequence(s),
+    color_mapper(s->color_mapper),
+    char_pix_per_world_unit(s->char_pix_per_world_unit)
+{
+  seq->setDrawable(copy_drawable(s->seq->drawable()));
+}
+
+GlSequence::GlSequence(const GlSequenceRef s)
+  : Sequence( (SequenceRef)s ),
+    color_mapper(s->color_mapper),
+    char_pix_per_world_unit(s->char_pix_per_world_unit)
+{
+  seq->setDrawable(copy_drawable(s->seq->drawable()));
 }
 
 GlSequence &GlSequence::operator=(const GlSequence & s)
 {
   if (this != &s) {
-    seq = s.seq;
-    seq_x = s.seq_x;
-    seq_y = s.seq_y;
-    seq_z = s.seq_z;
-    seq_height = s.seq_height;
+    Sequence::operator=(s);
+    seq->setDrawable(copy_drawable(s.seq->drawable()));
     color_mapper = s.color_mapper;
-    drawColor = s.drawColor;
     assert(char_pix_per_world_unit == s.char_pix_per_world_unit);
   }
   return *this;
 }
 
-boost::shared_ptr<Sequence> GlSequence::sequence()
+DrawableRef GlSequence::default_drawable()
 {
-  return seq;
+  ColorRef c(new Color(0.0, 0.0, 0.0));
+  DrawableRef d(new Drawable(0.0, 0.0, 1.0, default_height, c));
+  return d;
 }
 
-void GlSequence::setX(GLfloat value)
+DrawableRef GlSequence::copy_drawable(DrawableRef old_d)
 {
-  seq_x = value;
+  ColorRef c(old_d->color());
+  DrawableRef d(new Drawable(old_d));
+  // use the same color
+  d->setColor(c);
+  return d;
 }
 
-GLfloat GlSequence::x() const
+SeqSpanRef GlSequence::make_undefined_sequence_annotation(
+  Drawable::draw_func_ptr draw,
+  size_type start,
+  size_type count)
 {
-  return seq_x;
+  // create all the components of our annotation
+  // (should seq_i-start_i 
+  SeqSpanRef empty_seq(seq->subseq(start, count)); 
+  AnnotationsRef empty_seq_annot(new Annotations("null"));
+  DrawableRef drawable(default_drawable());
+  // glue everything to gether
+  drawable->setDrawFunction(draw);
+  empty_seq->setAnnotations(empty_seq_annot);
+  empty_seq->setDrawable(drawable);
+  return empty_seq;
 }
 
-GLfloat GlSequence::right() const
+void GlSequence::add_annotations_for_undefined_sequence(Drawable::draw_func_ptr draw)
+{
+  Sequence::const_iterator start_i = begin();
+  Sequence::const_iterator seq_i = begin();
+  Sequence::const_iterator end_i = end();
+  
+  Sequence::const_iterator start_block_i = end();
+  for(; seq_i != end_i; ++seq_i)
+  {
+    // need a better set of characters to serch for
+    if (*seq_i == 'N' or *seq_i == 'n') {
+      if (start_block_i == end_i) {
+        start_block_i = seq_i;
+      }
+    } else {
+      if (start_block_i != end_i) {
+        // we got one.
+        size_type start = start_block_i - start_i;
+        size_type count = seq_i - start_block_i;
+        // add the annotation
+        add_annotation(make_undefined_sequence_annotation(draw, start, count));        
+        // reset our counter...
+        start_block_i = end_i;
+      }
+    }
+  }
+  // catch stuff at the end
+  if( start_block_i != end_i ) {
+    size_type start = start_block_i - start_i;
+    size_type count = seq_i - start_block_i;
+    add_annotation(make_undefined_sequence_annotation(draw, start, count));        
+  }
+}
+
+
+void GlSequence::setX(float value)
+{
+  seq->drawable()->setX(value);
+}
+
+float GlSequence::x() const
 {
-  return size()+seq_x;
+  return seq->drawable()->x();
 }
 
 void GlSequence::setY(GLfloat value)
 {
-  seq_y = value;
+  seq->drawable()->setY(value);
 }
 
-GLfloat GlSequence::y() const
+float GlSequence::y() const
 {
-  return seq_y;
+  return seq->drawable()->y();
 }
 
-GLfloat GlSequence::height() const
+float GlSequence::z() const
 {
-  return seq_height;
+  return seq->drawable()->z();
+}
+
+float GlSequence::height() const
+{
+  return seq->drawable()->height();
+}
+
+GLfloat GlSequence::right() const
+{
+  return size()+x();
 }
 
 GLfloat GlSequence::size() const
 {
-  return seq->size();
+  return Sequence::size();
 }
 
 Sequence::size_type GlSequence::leftbase(GLfloat left) const
 {
-  left = ceil(left - seq_x);
+  left = ceil(left - 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;
 }
 
 Sequence::size_type GlSequence::rightbase(GLfloat right) const
 {
-  right = floor(right) - seq_x;
-  if (right > seq->size())
-    return seq->size();
+  right = floor(right) - x();
+  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
+Sequence::const_iterator 
+GlSequence::region_begin(GLfloat left, GLfloat right) const
 {
-  return seq->end();
+  if ( leftbase(left) > Sequence::size() or left > right )
+    return Sequence::end();
+  else
+    return Sequence::begin() + leftbase(left);
 }
 
 Sequence::const_iterator 
-GlSequence::sequence_begin(GLfloat left, GLfloat right) const
+GlSequence::region_end(GLfloat left, GLfloat right) const
 {
-  if ( leftbase(left) > seq->size() or left > right )
-    return seq->end();
+  if ( rightbase(right) > Sequence::size() or left > right )
+    return Sequence::end();
   else
-    return seq->begin() + leftbase(left);
+    return Sequence::begin() + rightbase(right); 
 }
 
-Sequence::const_iterator 
-GlSequence::sequence_end(GLfloat left, GLfloat right) const
+GlSequence GlSequence::subseq(size_type start, size_type count) const
 {
-  if ( rightbase(right) > seq->size() or left > right )
-    return seq->end();
-  else
-    return seq->begin() + rightbase(right); 
+  GlSequence new_seq(*this);
+  new_seq.seq = seq->subseq(start, count);
+  // make sure our subseq has a drawable attached to it
+  // perhaps we should figure out correct x,y,z,h coords
+  DrawableRef d(default_drawable());
+  // and default to our current color
+  ColorRef c(color());
+  d->setColor(c);
+  new_seq.seq->setDrawable(d);
+  copy_children(new_seq, start, count);
+  
+  return new_seq;
 }
 
+void GlSequence::setColor(ColorRef &c)
+{
+  seq->drawable()->setColor(c);
+}
 
-//! set default track draw color 
-void GlSequence::setColor(Color &c)
+ColorRef GlSequence::color()
 {
-  drawColor = c;
+  return seq->drawable()->color();
 }
 
-//! get default track draw color
-Color GlSequence::color()
+const ColorRef GlSequence::color() const
 {
-  return drawColor;
+  return seq->drawable()->color();
 }
 
 int GlSequence::get_viewport_width_in_pixels()
@@ -156,13 +238,13 @@ int GlSequence::get_viewport_width_in_pixels()
   return viewport[3]; // grab the viewport width
 }
 
-GLfloat GlSequence::get_pixel_width(GLfloat left, GLfloat right) const
+GLfloat GlSequence::pixelWidth(GLfloat left, GLfloat right)
 {
-  return get_pixel_width(left, right, get_viewport_width_in_pixels());
+  return pixelWidth(left, right, get_viewport_width_in_pixels());
 }
 
 GLfloat
-GlSequence::get_pixel_width(GLfloat left, GLfloat right, int vp_width) const
+GlSequence::pixelWidth(GLfloat left, GLfloat right, int vp_width)
 {
   return round((right-left)/vp_width);
 }
@@ -198,12 +280,12 @@ void GlSequence::draw(GLfloat left, GLfloat right) const
 
 void GlSequence::draw_box(GLfloat world_left, GLfloat world_right,
                           GLfloat left, GLfloat right, 
-                          GLfloat height, GLfloat z) const
+                          GLfloat height, GLfloat y, GLfloat z)
 {
-  GLfloat pixel_width = get_pixel_width(world_left, world_right);
+  GLfloat pixel_width = pixelWidth(world_left, world_right);
   GLfloat offset = height/2.0;
-  GLfloat top = seq_y + offset;
-  GLfloat bottom = seq_y - offset;
+  GLfloat top = y + offset;
+  GLfloat bottom = y - offset;
   
   // make our box be at least 1 pixel
   if ((right-left) < pixel_width) {
@@ -219,35 +301,40 @@ void GlSequence::draw_box(GLfloat world_left, GLfloat world_right,
 
 void GlSequence::draw_track(GLfloat left, GLfloat right) const
 {
-  glColor3fv(drawColor.get());
+  glColor3fv(color()->get());
   // draw main sequence track
-  draw_box(left, right, seq_x, seq_x+seq->size(), seq_height, 0.0);
+  draw_box(left, right, x(), x()+Sequence::size(), height(), y(), 0.0);
 }
 
 void GlSequence::draw_annotations(GLfloat left, GLfloat right) const
 {
   // draw annotations
-  GLfloat annotation_z = seq_z + 10.0;
-  const std::list<annot>& annots = seq->annotations();
-  const std::list<motif>& motifs = seq->motifs();
-  for (std::list<annot>::const_iterator annot_itor = annots.begin();
+  GLfloat annotation_z = z() + 10.0;
+  const SeqSpanRefList& annots = Sequence::annotations();
+  const MotifList& motifs = Sequence::motifs();
+  for (SeqSpanRefList::const_iterator annot_itor = annots.begin();
        annot_itor != annots.end();
        ++annot_itor)
   {
-    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);
+    DrawableRef drawable((*annot_itor)->drawable());
+    if (drawable and drawable->drawFunction()) {
+      assert((*annot_itor)->parent() == seq);
+      drawable->drawFunction()((*annot_itor), left, right); 
+    } else {
+      glColor3f(0.0, 0.8, 0.0);
+      draw_box(left, right, x()+(*annot_itor)->start(), x()+(*annot_itor)->stop(), 
+               height(), y(), annotation_z);
+    }
   }
   // if motifs?
-  for (std::list<motif>::const_iterator motifs_itor = motifs.begin();
+  for (MotifList::const_iterator motifs_itor = motifs.begin();
        motifs_itor != motifs.end();
        ++motifs_itor)
   {
     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);
+    draw_box(left, right, x()+motifs_itor->begin, x()+motifs_itor->end, 
+             height(), y(), annotation_z+1.0);
   }
-
 }
 
 // this way of drawing characters, came from the red open gl book
@@ -316,10 +403,10 @@ 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(color()->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 )
@@ -330,9 +417,9 @@ void GlSequence::draw_sequence(GLfloat left, GLfloat right) const
   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 + glyph_margin, seq_y, 1.0 );
+    glTranslatef( x()+leftbase(left) + basepair + glyph_margin, y(), 1.0 );
     glScalef(glyph_x_scale, 1.0, 1.0);
     switch (*seq_itor) {
       case 'A': case 'a':
@@ -362,10 +449,24 @@ void GlSequence::draw_sequence(GLfloat left, GLfloat right) const
 
 bool operator==(const GlSequence &left, const GlSequence &right)
 {
-  return ( (left.seq_x == right.seq_x) and
-           (left.seq_y == right.seq_y) and
-           (left.seq_z == right.seq_z) and
-           (left.seq_height == right.seq_height) and
-           (left.drawColor == right.drawColor));
+  return ( (left.x() == right.x()) and
+           (left.y() == right.y()) and
+           (left.z() == right.z()) and
+           (left.height() == right.height()) and
+           (left.color() == right.color()));
 }
 
+void draw_narrow_track(SeqSpanRef s, float left, float right)
+{
+  SeqSpanRef parent(s->parent());
+  DrawableRef parent_draw(parent->drawable());
+  float x( (parent_draw) ? parent_draw->x() : 0);
+  float y( (parent_draw) ? parent_draw->y() : 0);
+  float z( (parent_draw) ? parent_draw->z() : 10 );
+  float height( (parent_draw) ? parent_draw->height() : default_height ); 
+
+  glColor3f(1.0, 1.0, 1.0);
+  float hsmall = height * 3.0/4.0;
+  GlSequence::draw_box(left, right, x+s->start(), x+s->stop(), 
+                       hsmall, y, z+10);
+}
\ No newline at end of file