d883a4f49c90d3152122bd075537d1f0abab5fb3
[mussa.git] / alg / glsequence.cxx
1 #include "alg/glsequence.h"
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_width(s.size()),
15     seq_height(gl_track_height)
16 {
17   assert (seq.size() == seq_width);
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_width(s.seq_width),
26     seq_height(s.seq_height)
27 {
28   assert (seq.size() == seq_width);
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_width = s.seq_width;
39     seq_height = s.seq_height;
40   }
41   return *this;
42 }
43
44 const Sequence& GlSequence::sequence() const
45 {
46   return seq;
47 }
48
49 void GlSequence::setX(GLfloat value)
50 {
51   seq_x = value;
52 }
53
54 GLfloat GlSequence::x() const
55 {
56   return seq_x;
57 }
58
59 void GlSequence::setY(GLfloat value)
60 {
61   seq_y = value;
62 }
63
64 GLfloat GlSequence::y() const
65 {
66   return seq_y;
67 }
68
69 void GlSequence::setWidth(GLfloat value)
70 {
71   seq_width = value;
72 }
73
74 GLfloat GlSequence::width() const
75 {
76   return seq_width;
77 }
78
79
80 void GlSequence::draw(GLfloat left, GLfloat right) const
81 {
82   glLineWidth(seq_height);
83   glColor3f(0.0, 0.0, 0.0);
84   // draw main sequence track
85   glBegin(GL_LINES);
86     glVertex3f(seq_x,           seq_y, seq_z);
87     glVertex3f(seq_x+seq_width, seq_y, seq_z);
88     //clog << "drawing " << seq_x << " " << seq_y << " " << seq_width
89     //     << std::endl;
90   glEnd();
91   // draw annotations
92   GLfloat annotation_z = seq_z + 1.0;
93   std::list<annot> annots = seq.annotations();
94   for (std::list<annot>::const_iterator annot_itor = annots.begin();
95        annot_itor != annots.end();
96        ++annot_itor, ++annotation_z)
97   {
98     glColor3f(0.0, 0.5, 0.0);
99     glBegin(GL_LINES);
100       glVertex3f(annot_itor->start, seq_y, annotation_z);
101       glVertex3f(annot_itor->end  , seq_y, annotation_z);
102     glEnd();
103   }
104   draw_sequence(left, right);
105 }
106
107 const int PT = 1;
108 const int STROKE = 2;
109 const int END =3;
110
111 typedef struct charpoint {
112   GLfloat x, y;
113   int type;
114 } CP;
115
116 CP Adata[] = {
117   {0, 0, PT}, {0, 9, PT}, {1, 10, PT}, {4, 10, PT}, 
118   {5, 9, PT}, {5, 0, STROKE}, {0, 5, PT}, {5, 5, END}
119 };
120
121 CP Tdata[] = {
122   {2.5, 0, PT}, {2.5,10, STROKE}, {0, 10, PT}, {5,10, END}
123 };
124
125 CP Gdata[] = {
126   {5, 9, PT}, {4, 10, PT}, {1, 10, PT}, {0, 9, PT}, {0, 1, PT},
127   {1, 0, PT}, {5, 0, PT}, {5, 4, PT}, {3.5, 4, END}
128 };
129
130 CP Cdata[] = {
131   {5, 8, PT}, {3, 10, PT}, {2, 10, PT}, {0, 8, PT}, {0, 2, PT},
132   {2, 0, PT}, {3, 0, PT}, {5, 2, END}
133 };
134
135 CP Xdata[] = {{ 0, 10, PT}, {5,0,STROKE},{0,0,PT},{5,10,END}};
136 CP Ndata[] = {{ 0, 0, PT}, {0, 10, PT}, {5, 0, PT}, {5, 10, END}};
137
138 static void drawLetter(CP *l)
139 {
140   glBegin(GL_LINE_STRIP);
141   while(1) {
142     switch (l->type) {
143       case PT:
144         glVertex2fv(&l->x);
145         break;
146       case STROKE:
147         glVertex2fv(&l->x);
148         glEnd();
149         glBegin(GL_LINE_STRIP);
150         break;
151       case END:
152         glVertex2fv(&l->x);
153         glEnd();
154         return;
155         break;
156       default:
157          throw runtime_error("data structure failure");
158     }
159     l++;
160   }
161 }
162
163 void GlSequence::draw_sequence(GLfloat left, GLfloat right) const
164 {
165   int viewport[4];
166   glGetIntegerv(GL_VIEWPORT, viewport);
167   int port_width = viewport[3]; // grab the viewport width
168   GLfloat world_width = right - left;
169   int left_base = (left > 0) ? (int)ceil(left) : 0;
170   int right_base = (int)floor(right);
171   int render_count = (right_base < seq.size()) ? right_base : seq.size(); 
172   render_count -= left_base;
173
174   glLineWidth(0.01);
175   GLfloat char_width = 1.1;
176   GLfloat pixels_needed = char_width * world_width;
177
178   cout << "seq width needed " << pixels_needed 
179        << " port width " << port_width 
180        << " count " << render_count 
181        << " left " << left_base 
182        << " right " << right_base 
183        << " size " << seq.size() << endl;
184   // if the number of pixels taken up by rendering the characters 
185   // that'd show up in the current ortho width is less than the window
186   // width we can actually draw something 
187   if (pixels_needed < port_width and render_count > 0) {
188     cout << "rendering: ";
189     string bases = seq.subseq(left_base, render_count);
190     glColor3f(0.1, 0.1, 0.1);
191     for (string::size_type basepair = 0; basepair != bases.size(); ++basepair) 
192     {
193       glPushMatrix();
194       glTranslatef( left_base + basepair, seq_y+20, 1.0 );
195       glScalef(0.1, 1.0, 1.0);
196       switch (bases[basepair]) {
197         case 'A': case 'a':
198           drawLetter(Adata);
199         break;
200         case 'T': case 't':
201           drawLetter(Tdata);
202         break;
203         case 'G': case 'g':
204           drawLetter(Gdata);
205         break;
206         case 'C': case 'c':
207           drawLetter(Cdata);
208         break;
209         case 'N': case 'n':
210           drawLetter(Ndata);
211         break;
212         default:
213           drawLetter(Xdata);
214         break;
215       }
216       cout << bases[basepair];
217       glPopMatrix();
218     }
219     cout << endl;
220   }
221 }