1 |
/* Copyright (C) 2000 by Indraneel Majumdar<indraneel@indialine.org> */ |
2 |
|
3 |
/* GNU LESSER GENERAL PUBLIC LICENSE |
4 |
Version 2.1, February 1999 |
5 |
|
6 |
You should have received a copy of the GNU Lesser General Public |
7 |
License along with this library; if not, write to the Free Software |
8 |
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
9 |
*/ |
10 |
/* Program to plot Chaos Game Representation of a DNA or RNA sequence. */ |
11 |
|
12 |
|
13 |
/* this file should be linked with |
14 |
-lreadline -lncurses -lm -lvgagl -lvga -lpng -lz */ |
15 |
|
16 |
#include<stdio.h> |
17 |
#include<stdlib.h> |
18 |
#include<vgagl.h> |
19 |
#include<vga.h> |
20 |
#include<math.h> |
21 |
#include<readline/readline.h> |
22 |
#include<png.h> |
23 |
|
24 |
#define VGAMODE 12 /* 1024 x 768 at 256 colors */ |
25 |
#define TEXT 0 /* text mode */ |
26 |
|
27 |
/* initialise buffers for svgalib */ |
28 |
GraphicsContext *physicalscreen; |
29 |
GraphicsContext *templatescreen, *fileplotscreen, *randomplotscreen; |
30 |
|
31 |
/* stores probability data */ |
32 |
struct P_ATGC |
33 |
{ |
34 |
double a, t, g, c; |
35 |
} |
36 |
P; |
37 |
|
38 |
struct point |
39 |
{ |
40 |
double x, y; |
41 |
} |
42 |
A, T, G, C; |
43 |
|
44 |
/* stores input file name */ |
45 |
struct file_identity |
46 |
{ |
47 |
char name[105]; /* filepath and name has to be < 100 characters */ |
48 |
int flag; /* set this 0 for random plot */ |
49 |
} |
50 |
seqfile, outfile; |
51 |
|
52 |
/* global flags for user choice */ |
53 |
struct all_flags |
54 |
{ |
55 |
int file, prob, cycles, grid, seq, reload, counts, refresh, print; |
56 |
} |
57 |
flags; |
58 |
|
59 |
char sequence_table[16][16][5]; /* stores sequence chart */ |
60 |
int probability_table[16][16]; /* stores counts of bases per 10000 */ |
61 |
long int CYCLES, CYCLES_FIRST, CYCLES_LAST; /* iterations */ |
62 |
|
63 |
/* user input for probabilities for random plot */ |
64 |
void |
65 |
get_atgc_probabilities () |
66 |
{ |
67 |
vga_setmode (TEXT); |
68 |
P.a = P.t = P.g = P.c = 1.000000; |
69 |
while ((P.a + P.t + P.g) > 1.000001) |
70 |
{ |
71 |
printf ("\nEnter probabilities for A, T, G\n" |
72 |
"(probability for C is calculated automagically)\n" |
73 |
"Probabilities=>"); |
74 |
scanf ("%lf,%lf,%lf", &P.a, &P.t, &P.g); |
75 |
getchar (); /* discard the entered newline character */ |
76 |
} |
77 |
P.c = 1.000001 - (P.a + P.t + P.g); |
78 |
flags.prob = 1 - flags.prob; /* reverse global flag */ |
79 |
vga_setmode (VGAMODE); |
80 |
} |
81 |
|
82 |
/* user input for iterations */ |
83 |
int |
84 |
get_cycles () |
85 |
{ |
86 |
long int cycles; |
87 |
cycles = CYCLES_FIRST = 0; |
88 |
vga_setmode (TEXT); |
89 |
if (seqfile.flag == 0) |
90 |
{ |
91 |
printf ("\nEnter number of points to plot\n" "Points to plot=>"); |
92 |
scanf ("%d", &cycles); |
93 |
} |
94 |
else |
95 |
{ |
96 |
do |
97 |
{ /* filter user's input for errors, discard -ve numbers */ |
98 |
printf ("\nEnter start point for plot\n" "First base=>"); |
99 |
scanf ("%d", &CYCLES_FIRST); |
100 |
printf ("\nEnter end point for plot\n" |
101 |
"(enter '0' for entire file)\n" "Last base=>"); |
102 |
scanf ("%d", &cycles); |
103 |
} |
104 |
while ((cycles != 0) && ((cycles < 0) || (cycles < CYCLES_FIRST))); |
105 |
if ((cycles == 0) || (CYCLES_FIRST < 1)) |
106 |
CYCLES_FIRST = 1; /*so display looks better */ |
107 |
} |
108 |
getchar (); /* discard newline character */ |
109 |
vga_setmode (VGAMODE); |
110 |
flags.cycles = 1 - flags.cycles; /* reverse global flag */ |
111 |
return (cycles); /* return end point of loop */ |
112 |
} |
113 |
|
114 |
/* user's input for sequence input file */ |
115 |
void |
116 |
get_seqfile () |
117 |
{ |
118 |
FILE *fopen (), *file_pointer; /* to check if file exists */ |
119 |
char *filename_pointer, *malloc (); /*readline requires this */ |
120 |
int length; |
121 |
filename_pointer = malloc (100); /* length of filename<100 */ |
122 |
vga_setmode (TEXT); |
123 |
file_pointer = 0; /* initialise pointer to NULL */ |
124 |
seqfile.flag = 1; |
125 |
while ((file_pointer == 0) && (seqfile.flag == 1)) |
126 |
{ |
127 |
printf ("\nEnter full path of DNA sequence file\n" |
128 |
"(enter '*' for random number plot)\n"); |
129 |
filename_pointer = readline ("Filename=> "); /* makes it easy to locate files */ |
130 |
strncpy (seqfile.name, filename_pointer, 100); |
131 |
if (seqfile.name[0] == '*') |
132 |
{ |
133 |
sprintf (seqfile.name, "RANDOM NUMBER PLOT"); /* give a title to the plot */ |
134 |
seqfile.flag = 0; /* set flag for plot type */ |
135 |
} |
136 |
else |
137 |
{ |
138 |
length = strlen (seqfile.name); |
139 |
if (seqfile.name[length - 1] == ' ') |
140 |
seqfile.name[length - 1] = '\0'; /* discard last blank which maybe entered by readline input */ |
141 |
seqfile.flag = 1; /* set flag that disk file is being used */ |
142 |
file_pointer = fopen (seqfile.name, "r"); /* check if file exists */ |
143 |
} |
144 |
} |
145 |
if (seqfile.flag == 1) |
146 |
fclose (file_pointer); /* close file if exists */ |
147 |
free (filename_pointer); |
148 |
flags.file = 1 - flags.file; /* reverse global flag */ |
149 |
vga_setmode (VGAMODE); |
150 |
} |
151 |
|
152 |
/* generate (x,y) random point from 0 to 1 */ |
153 |
struct point |
154 |
get_random_point () |
155 |
{ |
156 |
struct point p; |
157 |
p.x = ((double) rand () / RAND_MAX); |
158 |
p.y = ((double) rand () / RAND_MAX); |
159 |
return (p); |
160 |
} |
161 |
|
162 |
/* make border of plot and print filename */ |
163 |
void |
164 |
draw_border () |
165 |
{ |
166 |
gl_line (A.x, A.y, T.x, T.y, 3); |
167 |
gl_line (T.x, T.y, G.x, G.y, 3); |
168 |
gl_line (G.x, G.y, C.x, C.y, 3); |
169 |
gl_line (C.x, C.y, A.x, A.y, 3); |
170 |
gl_setfontcolors (0, 32); |
171 |
gl_write (A.x - 25, A.y - 25, "DNA base 'A'"); |
172 |
gl_write (T.x - 25, T.y + 30, "DNA base 'T'"); |
173 |
gl_write (G.x - 50, G.y + 30, "DNA base 'G'"); |
174 |
gl_write (C.x - 50, C.y - 25, "DNA base 'C'"); |
175 |
gl_setfontcolors (0, 42); /*same color as file data */ |
176 |
gl_printf (A.x + 100, T.y + 50, "%s", seqfile.name); |
177 |
} |
178 |
|
179 |
/* draw the grid (lines are 37.5 pixels apart) */ |
180 |
void |
181 |
draw_grid () |
182 |
{ |
183 |
int num; |
184 |
float x, y, loopx, loopy = 0; |
185 |
x = C.x; |
186 |
y = T.y; |
187 |
loopx = A.x; |
188 |
loopy = A.y; |
189 |
num = 0; |
190 |
gl_setfontcolors (0, 52); |
191 |
gl_write (500, A.y - 20, "sequence resolution = 9 bp"); /* for a 600x600 pixel plot difference in base in any of last 9 bases gives different points (advertise this) */ |
192 |
while (loopx <= x) |
193 |
{ |
194 |
gl_line (loopx, A.y - 10, loopx, y + 10, 8); |
195 |
gl_printf (loopx, y + 15, "%d", num); /* grid number */ |
196 |
loopx = loopx + 37.5; |
197 |
num++; |
198 |
} |
199 |
num = 0; |
200 |
while (loopy <= y) |
201 |
{ |
202 |
gl_line (A.x - 10, loopy, x + 10, loopy, 8); |
203 |
gl_printf (x + 15, loopy, "%d", num); /* grid number */ |
204 |
loopy = loopy + 37.5; |
205 |
num++; |
206 |
} |
207 |
flags.grid = 1 - flags.grid; /* reverse global flag */ |
208 |
} |
209 |
|
210 |
/* plot random plot to virtual screen and copy to real screen (this makes plot and refresh faster)*/ |
211 |
void |
212 |
plot_random_sequence (long int cycles) |
213 |
{ |
214 |
long int loop; |
215 |
double a, t, g, c; |
216 |
struct point p, pix; |
217 |
gl_setcontext (templatescreen); /*change to template virtual screen */ |
218 |
gl_copyscreen (randomplotscreen); /*copy template to working virtual screen ie randomplotscreen */ |
219 |
gl_setcontext (randomplotscreen); /* change to working virtual screen */ |
220 |
a = P.a; |
221 |
t = a + P.t; |
222 |
g = t + P.g; |
223 |
c = g + P.c; /* convert user input to 0 to 1 */ |
224 |
loop = 0; |
225 |
pix.x = 600; |
226 |
pix.y = 350; |
227 |
while (loop < cycles) |
228 |
{ |
229 |
p = get_random_point (); |
230 |
/* test against user input probability and scale pixel to fit within borders. point is located midway between previous point and corner for chosen base. This is the CGR */ |
231 |
if (p.x <= a) |
232 |
{ |
233 |
pix.x = (pix.x + A.x) / 2; |
234 |
pix.y = (pix.y + A.y) / 2; |
235 |
} |
236 |
else if (p.x <= t) |
237 |
{ |
238 |
pix.x = (pix.x + T.x) / 2; |
239 |
pix.y = (pix.y + T.y) / 2; |
240 |
} |
241 |
else if (p.x <= g) |
242 |
{ |
243 |
pix.x = (pix.x + G.x) / 2; |
244 |
pix.y = (pix.y + G.y) / 2; |
245 |
} |
246 |
else if (p.x <= c) |
247 |
{ |
248 |
pix.x = (pix.x + C.x) / 2; |
249 |
pix.y = (pix.y + C.y) / 2; |
250 |
} |
251 |
gl_setpixel (pix.x, pix.y, 44); /*plot the pixel */ |
252 |
loop++; |
253 |
} |
254 |
gl_copyscreen (physicalscreen); /* copy to monitor or stdout */ |
255 |
gl_setcontext (physicalscreen); /* change working screen to real screen */ |
256 |
CYCLES = loop; /* record actual number of points plotted */ |
257 |
} |
258 |
|
259 |
/* plots CGR from disk file sequence to virtual screen and copies to real screen (makes plotting and refresh faster)*/ |
260 |
void |
261 |
plot_file_sequence (long int cycles) |
262 |
{ |
263 |
long int loop, base_count, first_base; |
264 |
int base, array_row, array_col, array_box, stop; |
265 |
int a, t, g, c; |
266 |
struct point pix; |
267 |
char file_header[200]; /* non sequence lines at start of file */ |
268 |
FILE *fopen (), *file_pointer; |
269 |
gl_setcontext (templatescreen); /* change to template virtual screen */ |
270 |
gl_copyscreen (fileplotscreen); /* copy template to working screen */ |
271 |
gl_setcontext (fileplotscreen); /* change to working virtual screen */ |
272 |
loop = stop = base_count = base = 0; |
273 |
first_base = CYCLES_FIRST - 1; |
274 |
a = t = g = c = 0; |
275 |
/* initialise the counts table for each new plot */ |
276 |
for (array_row = 0; array_row < 16; array_row++) |
277 |
{ |
278 |
for (array_col = 0; array_col < 16; array_col++) |
279 |
{ |
280 |
probability_table[array_row][array_col] = 0; |
281 |
} |
282 |
} |
283 |
pix.x = 600; |
284 |
pix.y = 350; |
285 |
file_pointer = fopen (seqfile.name, "r"); /* open file for reading */ |
286 |
fgets (file_header, 200, file_pointer); /* first line is not checked for sequence (assumed to contain file information and is shown on display */ |
287 |
gl_setfontcolors (0, 42); |
288 |
gl_write (50, T.y + 60, "File data:"); |
289 |
gl_printf (50, T.y + 80, "%s", file_header); /* show first line */ |
290 |
base = getc (file_pointer); /* get first base of next line */ |
291 |
base = tolower (base); /* convert to lowercase */ |
292 |
/* sequence description must start with a,t,u,g,c, or blank (fasta format), please write checkpoints for other sequence formats and add here */ |
293 |
while ((base != 'a') && (base != 't') && (base != 'u') && (base != 'g') |
294 |
&& (base != 'c') && (base != ' ')) |
295 |
{ |
296 |
ungetc (base, file_pointer); /* move back */ |
297 |
fgets (file_header, 200, file_pointer); /* remove the whole line */ |
298 |
base = getc (file_pointer); /* get first base of next line */ |
299 |
base = tolower (base); |
300 |
} |
301 |
ungetc (base, file_pointer); /* move back if sequence has started */ |
302 |
/* check for EOF and whether last base to plot has been reached */ |
303 |
while ((stop == 0) && ((base = getc (file_pointer)) != EOF)) |
304 |
{ |
305 |
base = tolower (base); |
306 |
if ((base == 'a') || (base == 't') || (base == 'u') || (base == 'g') |
307 |
|| (base == 'c')) |
308 |
{ |
309 |
/* check whether base is to be plotted (user input for start and end points) */ |
310 |
if ((cycles == 0) || ((loop >= first_base) && (loop < cycles))) |
311 |
{ |
312 |
/* set pixel according to CGR theory (point is halfway between previous point and corner of current chosen base) */ |
313 |
if (base == 'a') |
314 |
{ |
315 |
pix.x = (pix.x + A.x) / 2; |
316 |
pix.y = (pix.y + A.y) / 2; |
317 |
a++; |
318 |
} |
319 |
else if ((base == 't') || (base == 'u')) |
320 |
{ |
321 |
pix.x = (pix.x + T.x) / 2; |
322 |
pix.y = (pix.y + T.y) / 2; |
323 |
t++; |
324 |
} |
325 |
else if (base == 'g') |
326 |
{ |
327 |
pix.x = (pix.x + G.x) / 2; |
328 |
pix.y = (pix.y + G.y) / 2; |
329 |
g++; |
330 |
} |
331 |
else if (base == 'c') |
332 |
{ |
333 |
pix.x = (pix.x + C.x) / 2; |
334 |
pix.y = (pix.y + C.y) / 2; |
335 |
c++; |
336 |
} |
337 |
gl_setpixel (pix.x, pix.y, 44); /* plot the pixel */ |
338 |
array_row = (pix.x - 300) / 37.5; |
339 |
array_col = (pix.y - 50) / 37.5; /* scale the pixel location and update the counts table */ |
340 |
probability_table[array_row][array_col]++; |
341 |
base = 'x'; /* make base non atugc blank */ |
342 |
base_count++; /* update count of actual points plotted */ |
343 |
} |
344 |
loop++; /* increment counter for bases checked */ |
345 |
if ((cycles != 0) && (loop == cycles)) |
346 |
stop = 1; /* check for end point */ |
347 |
} /* no counter increments for non atugc even if not plotted */ |
348 |
} |
349 |
fclose (file_pointer); |
350 |
CYCLES = base_count; /* record actual points plotted */ |
351 |
CYCLES_LAST = loop; /* record actual last base checked */ |
352 |
if (base_count == 0) |
353 |
CYCLES_FIRST = base_count = 1; /* if user input for first base was > total bases in file */ |
354 |
/* calculate probability of atgc based on total points plotted */ |
355 |
P.a = (double) a / base_count; |
356 |
P.t = (double) t / base_count; |
357 |
P.g = (double) g / base_count; |
358 |
P.c = (double) c / base_count; |
359 |
/* prepare counts table to show counts out of 10000 */ |
360 |
for (array_row = 0; array_row < 16; array_row++) |
361 |
{ |
362 |
for (array_col = 0; array_col < 16; array_col++) |
363 |
{ |
364 |
/* convert display to integer */ |
365 |
array_box = |
366 |
(probability_table[array_row][array_col] * 10000) / base_count; |
367 |
/* update table */ |
368 |
probability_table[array_row][array_col] = array_box; |
369 |
} |
370 |
} |
371 |
gl_copyscreen (physicalscreen); /* copy working screen to monitor or stdout */ |
372 |
gl_setcontext (physicalscreen); /* change working screen to real screen */ |
373 |
} |
374 |
|
375 |
/* to show the sequence chart at the drop of a finger */ |
376 |
void |
377 |
make_sequence_table () |
378 |
{ |
379 |
int row, col, position; |
380 |
int base; |
381 |
row = col = position = 0; |
382 |
/* pass all calculations to helper for all 1024 positions */ |
383 |
while (position < 4) |
384 |
{ /* no place to print more than 4 bases */ |
385 |
while (col < 16) |
386 |
{ |
387 |
while (row < 16) |
388 |
{ |
389 |
base = help_sequence_table (col, row, position); |
390 |
sequence_table[row][col][position] = base; |
391 |
row++; |
392 |
} |
393 |
col++; |
394 |
row = 0; |
395 |
} |
396 |
position++; |
397 |
col = 0; |
398 |
} |
399 |
/* add a blank to all ends so they can be printed as strings */ |
400 |
row = col = 0; |
401 |
while (col < 16) |
402 |
{ |
403 |
while (row < 16) |
404 |
{ |
405 |
sequence_table[row][col][4] = '\0'; |
406 |
row++; |
407 |
} |
408 |
col++; |
409 |
row = 0; |
410 |
} |
411 |
} |
412 |
|
413 |
/* this returns value of a base at any position of any table */ |
414 |
/* (first position is position 0 and so on..) */ |
415 |
int |
416 |
help_sequence_table (int row, int col, int position) |
417 |
{ |
418 |
int base; |
419 |
int divisor, checkx, checky; /*checkxy - even is 0, odd is 1 */ |
420 |
divisor = pow (2, position); /* convert divisor to position power of 2 */ |
421 |
row = row / divisor; |
422 |
col = col / divisor; /* now it is easier to handle as everything becomes odd or even */ |
423 |
checkx = checky = 1; |
424 |
/* check odd or even */ |
425 |
if ((row % 2) == 0) |
426 |
checkx = 0; |
427 |
if ((col % 2) == 0) |
428 |
checky = 0; |
429 |
/* the bottom is true when ATGC represents a square */ |
430 |
if ((checkx == 0) && (checky == 0)) |
431 |
base = 'A'; |
432 |
else if ((checkx == 1) && (checky == 0)) |
433 |
base = 'T'; |
434 |
else if ((checkx == 1) && (checky == 1)) |
435 |
base = 'G'; |
436 |
else if ((checkx == 0) && (checky == 1)) |
437 |
base = 'C'; |
438 |
return (base); /* done */ |
439 |
} |
440 |
|
441 |
/* display the table when asked */ |
442 |
void |
443 |
display_sequence_table () |
444 |
{ |
445 |
int row, col, startx, starty; |
446 |
gl_setfontcolors (0, 92); |
447 |
gl_printf (20, 200, "(sequence ending for point)"); |
448 |
startx = 302; |
449 |
starty = 53; |
450 |
row = col = 0; |
451 |
while (col < 16) |
452 |
{ |
453 |
while (row < 16) |
454 |
{ |
455 |
/* print the table as strings of 4 chars */ |
456 |
gl_write (startx + row * 37.5, starty + col * 37.5, |
457 |
sequence_table[row][col]); |
458 |
/* oops, must have goofed up somewhere, interchange row and col for correct output */ |
459 |
row++; |
460 |
} |
461 |
col++; |
462 |
row = 0; |
463 |
} |
464 |
} |
465 |
|
466 |
/* display the counts table */ |
467 |
void |
468 |
display_probability_table () |
469 |
{ |
470 |
int row, col, startx, starty; |
471 |
gl_setfontcolors (0, 40); |
472 |
gl_printf (20, 220, "(counts per 10'000 total points)"); |
473 |
gl_setfontcolors (31, 40); /* change background to white to see better */ |
474 |
startx = 302; |
475 |
starty = 63; |
476 |
row = col = 0; |
477 |
while (col < 16) |
478 |
{ |
479 |
while (row < 16) |
480 |
{ |
481 |
gl_printf (startx + row * 37.5, starty + col * 37.5, "%d", |
482 |
probability_table[row][col]); |
483 |
row++; |
484 |
} |
485 |
col++; |
486 |
row = 0; |
487 |
} |
488 |
} |
489 |
|
490 |
/* display total probability, points plotted, user's input of first base, lase base checked */ |
491 |
void |
492 |
display_parameters () |
493 |
{ |
494 |
gl_setfontcolors (0, 48); |
495 |
gl_write (50, 60, "Probabilities are:"); |
496 |
gl_printf (20, 80, "A = %6.4f", P.a); |
497 |
gl_printf (20, 100, "T = %6.4f", P.t); |
498 |
gl_printf (150, 100, "G = %6.4f", P.g); |
499 |
gl_printf (150, 80, "C = %6.4f", P.c); |
500 |
gl_printf (50, 120, "Total points: %d", CYCLES); /* total points plotted */ |
501 |
/* only if disk file is read */ |
502 |
if (seqfile.flag == 1) |
503 |
{ |
504 |
gl_printf (20, 140, "First base: %d", CYCLES_FIRST); /* user's input echoed with minor changes in case of wrong input */ |
505 |
gl_printf (20, 160, "Last base: %d", CYCLES_LAST); /* display last base actually checked */ |
506 |
} |
507 |
} |
508 |
|
509 |
/*keep template for use by fileplotscreen and randomplotscreen for fresh plots*/ |
510 |
void |
511 |
make_templatescreen () |
512 |
{ |
513 |
gl_setcontext (templatescreen); /*change to virtual screen */ |
514 |
gl_clearscreen (0); |
515 |
gl_setfontcolors (0, 44); |
516 |
gl_printf (5, 5, |
517 |
" HELP MENU: file iterations probability counts grid sequence refresh Print Reload about quit"); |
518 |
gl_setfontcolors (0, vga_white ()); |
519 |
gl_printf (50, 650, "dnacgr-0.2"); |
520 |
draw_grid (); |
521 |
draw_border (); |
522 |
gl_setcontext (physicalscreen); /*change to real screen */ |
523 |
} |
524 |
|
525 |
/* prepare virtual screens randomplotscreen and fileplot screen and show on real screen */ |
526 |
void |
527 |
make_display (long int cycles) |
528 |
{ |
529 |
make_templatescreen (); |
530 |
if (seqfile.flag == 0) |
531 |
{ |
532 |
plot_random_sequence (cycles); |
533 |
} |
534 |
else |
535 |
plot_file_sequence (cycles); |
536 |
display_parameters (); |
537 |
flags.reload = 1 - flags.reload; /* reverse global flag */ |
538 |
} |
539 |
|
540 |
/* to save time just refresh the screen, do not replot any data */ |
541 |
void |
542 |
display_refresh (int input_grid) |
543 |
{ |
544 |
if (seqfile.flag == 0) |
545 |
{ |
546 |
gl_setcontext (randomplotscreen); |
547 |
gl_copyscreen (physicalscreen); |
548 |
gl_setcontext (physicalscreen); |
549 |
} |
550 |
else |
551 |
{ |
552 |
gl_setcontext (fileplotscreen); |
553 |
gl_copyscreen (physicalscreen); |
554 |
gl_setcontext (physicalscreen); |
555 |
} |
556 |
if (input_grid == 1) |
557 |
{ |
558 |
draw_grid (); |
559 |
draw_border (); |
560 |
} /* draw grid if required */ |
561 |
display_parameters (); /* parameters are always displayed */ |
562 |
flags.refresh = 1 - flags.refresh; /* reverse global flag */ |
563 |
} |
564 |
|
565 |
/* save the color table to file for use with screen memory dump */ |
566 |
/* unused code */ |
567 |
void |
568 |
save_color_table () |
569 |
{ |
570 |
FILE *fopen (), *file_pointer; |
571 |
int color, r, g, b; |
572 |
color = 0; |
573 |
file_pointer = fopen ("clrtbl.dnacgr", "w"); |
574 |
for (color = 0; color < 256; color++) |
575 |
{ |
576 |
gl_getpalettecolor (color, &r, &g, &b); |
577 |
fprintf (file_pointer, "%d\t%d\t%d\t%d\n", color, r * 4, g * 4, b * 4); |
578 |
} |
579 |
fclose (file_pointer); |
580 |
} |
581 |
|
582 |
/* ask user for output filename. .png extension is added automatically */ |
583 |
void |
584 |
get_output_filename () |
585 |
{ |
586 |
char *filename_pointer, *malloc (); |
587 |
vga_setmode (TEXT); |
588 |
filename_pointer = malloc (100); |
589 |
printf ("\nEnter new filename for saving image file\n"); |
590 |
filename_pointer = readline ("Filename=> "); |
591 |
strncpy (outfile.name, filename_pointer, 100); |
592 |
strcat (outfile.name, ".png"); |
593 |
free (filename_pointer); |
594 |
vga_setmode (VGAMODE); |
595 |
} |
596 |
|
597 |
/* this just dumps screen memory to file, you need color tables to use this dump */ |
598 |
/* unused code */ |
599 |
void |
600 |
print_file () |
601 |
{ |
602 |
FILE *fopen (), *file_pointer; |
603 |
char *saved_screen_ptr, *malloc (); |
604 |
saved_screen_ptr = malloc (1024 * 768); |
605 |
gl_getbox (0, 0, 1024, 768, saved_screen_ptr); |
606 |
file_pointer = fopen (outfile.name, "w"); |
607 |
fwrite (saved_screen_ptr, 1, 1024 * 768, file_pointer); |
608 |
fclose (file_pointer); |
609 |
free (saved_screen_ptr); |
610 |
flags.print = 1 - flags.print; |
611 |
} |
612 |
|
613 |
/* print to png file. modified from code donated by Sergio Masci <sergio@titan.demon.co.uk> */ |
614 |
void |
615 |
print_png_file () |
616 |
{ |
617 |
FILE *fopen (), *fp; |
618 |
char *malloc (); |
619 |
int xred, xgreen, xblue; |
620 |
int adj, bits_per_colour, j; |
621 |
char *rp; |
622 |
png_struct *png_ptr; |
623 |
png_info *info_ptr; |
624 |
png_colorp palette; |
625 |
|
626 |
fp = fopen (outfile.name, "wb"); |
627 |
|
628 |
// allocate the necessary structures |
629 |
png_ptr = (png_struct *) malloc (sizeof (png_struct)); |
630 |
|
631 |
info_ptr = (png_info *) malloc (sizeof (png_info)); |
632 |
|
633 |
// initialize the structures |
634 |
png_info_init (info_ptr); |
635 |
png_write_init (png_ptr); |
636 |
|
637 |
// set up the output control |
638 |
png_init_io (png_ptr, fp); |
639 |
|
640 |
// set the file information here |
641 |
info_ptr->width = 1024; |
642 |
info_ptr->height = 768; |
643 |
info_ptr->bit_depth = 8; |
644 |
info_ptr->color_type = PNG_COLOR_TYPE_PALETTE; |
645 |
|
646 |
//---------------------- |
647 |
|
648 |
// set the palette |
649 |
info_ptr->valid |= PNG_INFO_PLTE; |
650 |
info_ptr->palette = (png_color *) malloc (256 * sizeof (png_color)); |
651 |
info_ptr->num_palette = 256; |
652 |
|
653 |
|
654 |
|
655 |
bits_per_colour = 6; |
656 |
|
657 |
adj = 8 - bits_per_colour; |
658 |
|
659 |
|
660 |
for (j = 0; j < 256; j++) |
661 |
{ |
662 |
vga_getpalette (j, &xred, &xgreen, &xblue); |
663 |
|
664 |
info_ptr->palette[j].red = xred << adj; |
665 |
info_ptr->palette[j].green = xgreen << adj; |
666 |
info_ptr->palette[j].blue = xblue << adj; |
667 |
} |
668 |
|
669 |
// write the file information |
670 |
png_write_info (png_ptr, info_ptr); |
671 |
|
672 |
rp = malloc (1024); |
673 |
|
674 |
for (j = 0; j < 768; j++) |
675 |
{ |
676 |
gl_getbox (0, j, 1024, 1, rp); |
677 |
|
678 |
// Write a row at a time. |
679 |
png_write_rows (png_ptr, &rp, 1); |
680 |
} |
681 |
|
682 |
free (rp); |
683 |
|
684 |
//---------------------- |
685 |
|
686 |
// write the rest of the file |
687 |
png_write_end (png_ptr, NULL); |
688 |
|
689 |
// clean up after the write, and free any memory allocated |
690 |
png_write_destroy (png_ptr); |
691 |
|
692 |
if (info_ptr->palette) |
693 |
{ // a palette was used, so free it |
694 |
free (info_ptr->palette); |
695 |
} |
696 |
|
697 |
// free the structures |
698 |
free (png_ptr); |
699 |
free (info_ptr); |
700 |
|
701 |
fclose (fp); |
702 |
} |
703 |
|
704 |
|
705 |
/* add your name here if you add a significant functionality to this code */ |
706 |
/* do not change the copyright notice */ |
707 |
void |
708 |
show_about_screen () |
709 |
{ |
710 |
int key; |
711 |
vga_setmode (VGAMODE); |
712 |
gl_clearscreen (31); |
713 |
gl_setfontcolors (31, 0); |
714 |
gl_printf (360, 250, |
715 |
" DNA-CGR (version 0.2)\nProgram to visualise patterns in DNA\n\n Copyright (C) 2000\n\n by\n\n Indraneel Majumdar\n\n <indraneel@123india.com>\n\n\n Copyright Policy - GNU-LGPL\n\n (see file LGPL-2.1 for details)\n\n (press 'L' to show License)"); |
716 |
key = getchar (); |
717 |
if (key == 'L') |
718 |
{ |
719 |
vga_setmode (TEXT); |
720 |
system ("/usr/bin/less /usr/share/common-licenses/LGPL-2.1"); |
721 |
vga_setmode (VGAMODE); |
722 |
} |
723 |
} |
724 |
|
725 |
/* background process to handle all keypresses */ |
726 |
void |
727 |
user_request_handler () |
728 |
{ |
729 |
long int cycles; |
730 |
int user_key; |
731 |
struct all_flags input; |
732 |
/* set initial values of local flags for first run */ |
733 |
input.file = 0; |
734 |
input.prob = 1; |
735 |
input.cycles = 0; |
736 |
input.grid = 0; |
737 |
input.seq = 0; |
738 |
input.reload = 0; |
739 |
input.counts = 0; |
740 |
input.refresh = 1; |
741 |
input.print = 1; |
742 |
user_key = 'x'; |
743 |
while (user_key != 'q') |
744 |
{ |
745 |
switch (user_key) |
746 |
{ |
747 |
case 'f': |
748 |
input.file = 1 - input.file; |
749 |
input.reload = 1 - input.reload; /* reload file (replot) */ |
750 |
break; |
751 |
case 'p': |
752 |
if (seqfile.flag == 0) |
753 |
{ |
754 |
input.prob = 1 - input.prob; |
755 |
input.reload = 1 - input.reload; /* replot */ |
756 |
} |
757 |
break; |
758 |
case 'i': |
759 |
input.cycles = 1 - input.cycles; |
760 |
input.reload = 1 - input.reload; /* replot from file */ |
761 |
break; |
762 |
case 'g': |
763 |
input.grid = 1 - input.grid; |
764 |
if (input.grid == 1) |
765 |
{ |
766 |
draw_grid (); |
767 |
draw_border (); |
768 |
} |
769 |
else |
770 |
input.refresh = 1 - input.refresh; /* just refresh screen */ |
771 |
break; |
772 |
case 's': |
773 |
input.seq = 1 - input.seq; |
774 |
if (input.seq == 0) |
775 |
input.refresh = 1 - input.refresh; /*just refresh screen */ |
776 |
break; |
777 |
case 'R': |
778 |
input.reload = 1 - input.reload; /* user's request to reload file */ |
779 |
break; |
780 |
case 'c': |
781 |
if (seqfile.flag == 1) |
782 |
input.counts = 1 - input.counts; |
783 |
/* switch off counts display (refresh screen) */ |
784 |
if ((seqfile.flag == 1) && (input.counts == 0)) |
785 |
input.refresh = 1 - input.refresh; |
786 |
break; |
787 |
case 'r': |
788 |
input.refresh = 1 - input.refresh; /* refresh screen */ |
789 |
break; |
790 |
case 'P': |
791 |
get_output_filename (); |
792 |
input.refresh = 1 - input.refresh; |
793 |
input.print = 1 - input.print; |
794 |
break; |
795 |
case 'a': |
796 |
show_about_screen (); /* version, names of author(s), copyright */ |
797 |
input.refresh = 1 - input.refresh; |
798 |
break; |
799 |
default: |
800 |
break; |
801 |
} |
802 |
user_key = 'x'; |
803 |
/* do not change the sequence below (the sequence of operations is required at least for first run) */ |
804 |
if (input.file == flags.file) |
805 |
get_seqfile (); |
806 |
/* next step explicitly checks for probabilities on first run (probabilities are required only for random number plot) */ |
807 |
if ( |
808 |
((seqfile.flag == 0) && ((P.a + P.t + P.g + P.c) == 0) |
809 |
&& (input.prob = 1 - input.prob)) || ((seqfile.flag == 0) |
810 |
&& (input.prob == |
811 |
flags. |
812 |
prob))) |
813 |
get_atgc_probabilities (); |
814 |
if (input.cycles == flags.cycles) |
815 |
cycles = get_cycles (); /* iterations */ |
816 |
if (input.reload == flags.reload) |
817 |
make_display (cycles); /* replot */ |
818 |
if (input.refresh == flags.refresh) |
819 |
display_refresh (input.grid); /*just refresh */ |
820 |
if (input.seq == 1) |
821 |
display_sequence_table (); |
822 |
/* counts table displayed only if sequence file is used */ |
823 |
if ((seqfile.flag == 1) && (input.counts == 1)) |
824 |
display_probability_table (); |
825 |
user_key = vga_getkey (); /* read key without waiting */ |
826 |
if (input.print == flags.print) |
827 |
print_png_file (); |
828 |
} |
829 |
} |
830 |
|
831 |
int |
832 |
main () |
833 |
{ |
834 |
int x, y; |
835 |
x = y = 0; |
836 |
vga_init (); /* initialise display for svgalib */ |
837 |
if (vga_hasmode (VGAMODE) == 0) |
838 |
exit (1); /* check if mode 12 is supported */ |
839 |
/* set corner points of border */ |
840 |
A.x = 300; |
841 |
A.y = 50; |
842 |
T.x = 300; |
843 |
T.y = 650; |
844 |
G.x = 900; |
845 |
G.y = 650; |
846 |
C.x = 900; |
847 |
C.y = 50; |
848 |
srand (time (0)); /* initialise random number generator */ |
849 |
|
850 |
vga_setmode (VGAMODE); /* set 1024x768 at 256 colors */ |
851 |
|
852 |
/* define fileplotscreen as virtual screen */ |
853 |
gl_setcontextvgavirtual (VGAMODE); |
854 |
fileplotscreen = gl_allocatecontext (); |
855 |
gl_getcontext (fileplotscreen); |
856 |
|
857 |
/* define randomplotscreen as virtual screen */ |
858 |
gl_setcontextvgavirtual (VGAMODE); |
859 |
randomplotscreen = gl_allocatecontext (); |
860 |
gl_getcontext (randomplotscreen); |
861 |
|
862 |
/* define templatescreen as virtual screen */ |
863 |
gl_setcontextvgavirtual (VGAMODE); |
864 |
templatescreen = gl_allocatecontext (); |
865 |
gl_getcontext (templatescreen); |
866 |
|
867 |
/* define physicalscreen as real screen */ |
868 |
gl_setcontextvga (VGAMODE); |
869 |
physicalscreen = gl_allocatecontext (); |
870 |
gl_getcontext (physicalscreen); |
871 |
|
872 |
gl_setcontext (physicalscreen); /* change to physicalscreen */ |
873 |
/* save_color_table(); output to file clrtbl.dnacgr */ |
874 |
|
875 |
/* define fonts globally */ |
876 |
gl_setfont (8, 8, gl_font8x8); |
877 |
gl_setwritemode (FONT_COMPRESSED + WRITEMODE_OVERWRITE); |
878 |
show_about_screen (); /* whom you can't flame if you lose your job */ |
879 |
make_sequence_table (); /* this is not modified later */ |
880 |
user_request_handler (); /* main loop */ |
881 |
|
882 |
/* free all memory */ |
883 |
gl_freecontext (fileplotscreen); |
884 |
gl_freecontext (randomplotscreen); |
885 |
gl_freecontext (templatescreen); |
886 |
vga_setmode (TEXT); /* just to be safe */ |
887 |
} |