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