load and display a motif list
[mussa.git] / alg / glsequence.cpp
1 #include "alg/glsequence.hpp"
2
3 #include <iostream>
4 #include <cassert>
5 #include <math.h>
6 #include <stdexcept>
7 using namespace std;
8
9 GlSequence::GlSequence(const Sequence &s, AnnotationColors& cm) 
10   : seq(s),
11     seq_x(0.0), 
12     seq_y(0.0), 
13     seq_z(1.0), 
14     seq_height(12.0),
15     color_mapper(cm),
16     drawColor(0.0, 0.0, 0.0),
17     char_pix_per_world_unit(5.0)
18 {
19 }
20
21 GlSequence::GlSequence(const GlSequence &s)
22   : seq(s.seq),
23     seq_x(s.seq_x),
24     seq_y(s.seq_y),
25     seq_z(s.seq_z),
26     seq_height(s.seq_height),
27     color_mapper(s.color_mapper),
28     drawColor(s.drawColor),
29     char_pix_per_world_unit(s.char_pix_per_world_unit)
30 {
31 }
32
33 GlSequence &GlSequence::operator=(const GlSequence & s)
34 {
35   if (this != &s) {
36     const_cast<Sequence &>(seq) = s.seq;
37     seq_x = s.seq_x;
38     seq_y = s.seq_y;
39     seq_z = s.seq_z;
40     seq_height = s.seq_height;
41     color_mapper = s.color_mapper;
42     drawColor = s.drawColor;
43     assert(char_pix_per_world_unit == s.char_pix_per_world_unit);
44   }
45   return *this;
46 }
47
48 const Sequence& GlSequence::sequence() const
49 {
50   return seq;
51 }
52
53 void GlSequence::setX(GLfloat value)
54 {
55   seq_x = value;
56 }
57
58 GLfloat GlSequence::x() const
59 {
60   return seq_x;
61 }
62
63 void GlSequence::setY(GLfloat value)
64 {
65   seq_y = value;
66 }
67
68 GLfloat GlSequence::y() const
69 {
70   return seq_y;
71 }
72
73 GLfloat GlSequence::length() const
74 {
75   return seq.size();
76 }
77
78 Sequence::size_type GlSequence::leftbase(GLfloat left) const
79 {
80   assert (seq_x == 0);
81   left = ceil(left);
82   if (left < seq_x)
83     return 0;
84   else
85     return (Sequence::size_type)left;
86 }
87
88 Sequence::size_type GlSequence::rightbase(GLfloat right) const
89 {
90   assert (seq_x == 0);
91   right = floor(right);
92   if (right > seq.size())
93     return seq.size();
94   else
95     return (Sequence::size_type)right;
96 }
97
98 Sequence::const_iterator GlSequence::sequence_begin() const
99 {
100   return seq.begin();
101 }
102
103 Sequence::const_iterator GlSequence::sequence_end() const
104 {
105   return seq.end();
106 }
107
108 Sequence::const_iterator 
109 GlSequence::sequence_begin(GLfloat left, GLfloat right) const
110 {
111   // the following code will be wrong when sequences can be slid around
112   // so make sure we break.
113   assert (seq_x == 0);
114
115   if ( leftbase(left) > seq.size() or left > right )
116     return seq.end();
117   else
118     return seq.begin() + leftbase(left);
119 }
120
121 Sequence::const_iterator 
122 GlSequence::sequence_end(GLfloat left, GLfloat right) const
123 {
124   // the following code will be wrong when sequences can be slid around
125   // so make sure we break.
126   assert (seq_x == 0);
127
128   if ( rightbase(right) > seq.size() or left > right )
129     return seq.end();
130   else
131     return seq.begin() + rightbase(right); 
132 }
133
134
135 //! set default track draw color 
136 void GlSequence::setColor(Color &c)
137 {
138   drawColor = c;
139 }
140
141 //! get default track draw color
142 Color GlSequence::color()
143 {
144   return drawColor;
145 }
146
147
148 int GlSequence::get_viewport_pixel_width()
149 {
150   int viewport[4];
151   glGetIntegerv(GL_VIEWPORT, viewport);
152   return viewport[3]; // grab the viewport width
153 }
154
155 bool GlSequence::is_sequence_renderable(GLfloat left, 
156                                         GLfloat right, 
157                                         int viewport_width) const
158 {
159   // if called with default argument, go get the viewable width
160   if (viewport_width == -1) {
161     viewport_width = get_viewport_pixel_width();
162   }
163   GLfloat world_width = right - left;
164   GLfloat pixels_needed = (char_pix_per_world_unit * world_width);
165
166   // if the number of pixels taken up by rendering the characters 
167   // that'd show up in the current ortho width is less than the window
168   // width we can actually draw something 
169    return pixels_needed < viewport_width;
170 }
171
172
173 void GlSequence::draw(GLfloat left, GLfloat right) const
174 {
175   if ( not is_sequence_renderable(left, right) ) {
176     draw_track(left, right);
177   } else {
178     draw_sequence(left, right);
179   }
180   draw_annotations(left, right);
181 }
182
183 void GlSequence::draw_box(GLfloat left, GLfloat right, 
184                           GLfloat height, GLfloat z) const
185 {
186   GLfloat offset = height/2.0;
187   GLfloat top = seq_y + offset;
188   GLfloat bottom = seq_y - offset;
189     
190   glBegin(GL_QUADS);
191     glVertex3f(left,  top,    z);
192     glVertex3f(left,  bottom, z);
193     glVertex3f(right, bottom, z);
194     glVertex3f(right, top,    z);
195   glEnd();
196 }
197 void GlSequence::draw_track(GLfloat left, GLfloat right) const
198 {
199   glColor3fv(drawColor.get());
200   // draw main sequence track
201   draw_box(seq_x, seq_x+seq.size(), seq_height, 0.0);
202 }
203
204 void GlSequence::draw_annotations(GLfloat left, GLfloat right) const
205 {
206   // draw annotations
207   glLineWidth(seq_height);
208   GLfloat annotation_z = seq_z + 1.0;
209   const std::list<annot>& annots = seq.annotations();
210   const std::list<motif>& motifs = seq.motifs();
211   for (std::list<annot>::const_iterator annot_itor = annots.begin();
212        annot_itor != annots.end();
213        ++annot_itor, ++annotation_z)
214   {
215     glColor3f(0.0, 0.5, 0.0);
216     draw_box(seq_x+annot_itor->start, seq_x+annot_itor->end, 
217              seq_height, annotation_z);
218   }
219   // if motifs?
220   for (std::list<motif>::const_iterator motifs_itor = motifs.begin();
221        motifs_itor != motifs.end();
222        ++motifs_itor, ++annotation_z)
223   {
224     glColor3fv(color_mapper.lookup("motif", motifs_itor->sequence).get());
225     draw_box(seq_x+motifs_itor->start, seq_x+motifs_itor->end, 
226              seq_height, annotation_z);
227   }
228
229 }
230
231
232 const int PT = 1;
233 const int STROKE = 2;
234 const int END =3;
235
236 typedef struct charpoint {
237   GLfloat x, y;
238   int type;
239 } CP;
240
241 CP Adata[] = {
242   {0, -5, PT}, {2.5, 5, PT}, {5, -5, STROKE}, 
243   {0.75, -2, PT}, {4.25, -2, END}
244 };
245
246 CP Tdata[] = {
247   {2.5, -5, PT}, {2.5,5, STROKE}, {0, 5, PT}, {5, 5, END}
248 };
249
250 CP Gdata[] = {
251   {5, 3, PT}, {3, 5, PT}, {2, 5, PT}, {0, 3, PT}, {0, -3, PT},
252   {2, -5, PT}, {3, -5, PT}, {5, -3, STROKE}, 
253   {2.5, -1, PT}, {5, -1,PT}, {5, -5, END}
254 };
255
256 CP Cdata[] = {
257   {4.9, 3, PT}, {3, 5, PT}, {2, 5, PT}, {0, 3, PT}, {0, -3, PT},
258   {2, -5, PT}, {3, -5, PT}, {5, -3, END}
259 };
260
261 CP Xdata[] = {{ 0, 5, PT}, {5, -5,STROKE},{0,-5,PT},{5, 5, END}};
262 CP Ndata[] = {{ 0, -5, PT}, {0, 5, PT}, {5, -5, PT}, {5, 5, END}};
263
264 static void drawLetter(CP *l, GLfloat z)
265 {
266   glBegin(GL_LINE_STRIP);
267   while(1) {
268     switch (l->type) {
269       case PT:
270         glVertex3f(l->x, l->y, z);
271         break;
272       case STROKE:
273         glVertex3f(l->x, l->y, z);
274         glEnd();
275         glBegin(GL_LINE_STRIP);
276         break;
277       case END:
278         glVertex3f(l->x, l->y, z);
279         glEnd();
280         return;
281         break;
282       default:
283          throw runtime_error("data structure failure");
284     }
285     l++;
286   }
287 }
288
289 void GlSequence::draw_sequence(GLfloat left, GLfloat right) const
290 {
291   // FIXME: basically this needs to be greater than the number of annotations
292   const GLfloat z = 30;
293   glLineWidth(0.3);
294   glColor3fv(drawColor.get());
295
296   Sequence::const_iterator seq_itor = sequence_begin(left, right);
297   Sequence::const_iterator seq_end = sequence_end(left, right);
298   Sequence::size_type basepair = 0;
299
300   assert(seq_end - seq_itor >= 0);
301   while(seq_itor != seq_end)
302   {
303     assert ( basepair < seq.size() );
304     glPushMatrix();
305     glTranslatef( leftbase(left) + basepair, seq_y, 1.0 );
306     glScalef(0.1, 1.0, 1.0);
307     switch (*seq_itor) {
308       case 'A': case 'a':
309         drawLetter(Adata, z);
310         break;
311       case 'T': case 't':
312         drawLetter(Tdata, z);
313         break;
314       case 'G': case 'g':
315         drawLetter(Gdata, z);
316         break;
317       case 'C': case 'c':
318         drawLetter(Cdata, z);
319         break;
320       case 'N': case 'n':
321         drawLetter(Ndata, z);
322         break;
323       default:
324         drawLetter(Xdata, z);
325         break;
326     }
327     glPopMatrix();
328     ++seq_itor;
329     ++basepair;
330   }
331 }
332
333 bool operator==(const GlSequence &left, const GlSequence &right)
334 {
335   return ( (left.seq_x == right.seq_x) and
336            (left.seq_y == right.seq_y) and
337            (left.seq_z == right.seq_z) and
338            (left.seq_height == right.seq_height) and
339            (left.drawColor == right.drawColor));
340 }
341