Add Russian translation provided by Валерий Крувялис <valkru@mail.ru>
[xiph-mirror.git] / chirptest / chirpgraph.c
blob9f5523d7ecfb19188f0367e2e5ad3b2519ed4842
1 /********************************************************************
2 * *
3 * THIS FILE IS PART OF THE OggGhost SOFTWARE CODEC SOURCE CODE. *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggGhost SOURCE CODE IS (C) COPYRIGHT 2007-2011 *
9 * by the Xiph.Org Foundation http://www.xiph.org/ *
10 * *
11 ********************************************************************
13 function: graphing code for chirp tests
14 last mod: $Id$
16 ********************************************************************/
18 #define _GNU_SOURCE
19 #include <math.h>
20 #include "chirp.h"
21 #include "chirpgraph.h"
22 #include "scales.h"
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <cairo/cairo.h>
27 #include <pthread.h>
29 /********************** colors for graphs *********************************/
31 void set_iter_color(cairo_t *cC, int ret, float a){
32 if (ret>100){
33 cairo_set_source_rgba(cC,1,1,1,a); /* white */
34 }else if (ret>50){ /* 51(black)-100(white) */
35 cairo_set_source_rgba(cC,(ret-50)*.02,(ret-50)*.02,(ret-50)*.02,a);
36 }else if (ret>30){ /* 31(red) - 50(black) */
37 cairo_set_source_rgba(cC,1-(ret-30)*.05,0,0,a);
38 }else if (ret>10){ /* 11(yellow) - 30(red) */
39 cairo_set_source_rgba(cC,1,1-(ret-10)*.05,0,a);
40 }else if (ret>4){ /* 5 (green) - 10 (yellow) */
41 cairo_set_source_rgba(cC,(ret-5)*.15+.25,1,0,a);
42 }else if (ret==4){ /* 4 brighter cyan */
43 cairo_set_source_rgba(cC,0,.8,.4,a);
44 }else if (ret==3){ /* 3 cyan */
45 cairo_set_source_rgba(cC,0,.6,.6,a);
46 }else if (ret==2){ /* 2 dark cyan */
47 cairo_set_source_rgba(cC,0,.4,.8,a);
48 }else if (ret==1){ /* 1 blue */
49 cairo_set_source_rgba(cC,.1,.2,1,a);
50 }else{ /* dark blue */
51 cairo_set_source_rgba(cC,.2,0,1,a);
55 void set_iter_text_color(cairo_t *cC, int ret){
56 if (ret>75){
57 cairo_set_source_rgba(cC,0,0,0,1); /* black on white*/
58 }else if (ret>35){
59 cairo_set_source_rgba(cC,1,1,1,1); /* white on red/black */
60 }else if (ret>3){
61 cairo_set_source_rgba(cC,0,0,0,1); /* black on cyan */
62 }else{
63 cairo_set_source_rgba(cC,1,1,1,1); /* white on dark */
67 void set_error_color(cairo_t *c, float err,float a){
68 if(isnan(err) || fabs(err)>1.){
69 cairo_set_source_rgba(c,1,1,1,a); /* white */
70 }else{
71 err=fabs(err);
72 if(err>.1){
73 cairo_set_source_rgba(c,(err-.1)/.9,(err-.1)/.9,(err-.1)/.9,a); /* white->black */
74 }else if(err>.01){
75 cairo_set_source_rgba(c,1.-((err-.01)/.09),0,0,a); /* black->red */
76 }else if(err>.001){
77 cairo_set_source_rgba(c,1,1.-((err-.001)/.009),0,a); /* red->yellow */
78 }else if(err>.0001){
79 cairo_set_source_rgba(c,((err-.0001)/.0009),1,0,a); /* yellow->green */
80 }else if(err>.00001){
81 cairo_set_source_rgba(c,0,1,1.-((err-.00001)/.00009),a); /* green->cyan */
82 }else if(err>.000001){
83 cairo_set_source_rgba(c,.2-((err-.000001)/.000009)*.2,
84 ((err-.000001)/.000009)*.8+.2,1,a); /* cyan->blue */
85 }else{
86 cairo_set_source_rgba(c,.1,.1,1,a); /* blue */
91 void set_error_text_color(cairo_t *c, float err){
92 if(isnan(err) || fabs(err)>1.){
93 cairo_set_source_rgba(c,0,0,0,1); /* black on white */
94 }else{
95 err=fabs(err);
96 if(err>.5){
97 cairo_set_source_rgba(c,0,0,0,1); /* black on white */
98 }else if(err>.02){
99 cairo_set_source_rgba(c,1,1,1,1); /* white */
100 }else if(err>.000005){
101 cairo_set_source_rgba(c,0,0,0,1); /* black */
102 }else{
103 cairo_set_source_rgba(c,1,1,1,1); /* white */
108 /********* draw everything in the graph except the graph data itself *******/
110 static float fontsize=12;
111 static int x0s,x1s,xmajor,xmajorf;
112 static int y0s,y1s,ymajor,ymajorf;
114 /* computed configuration globals */
115 int leftpad=0;
116 static int rightpad=0;
117 int toppad=0;
118 static int bottompad=0;
119 static float legendy=0;
120 static float legendh=0;
121 static int pic_w=0;
122 static int pic_h=0;
123 static float titleheight=0.;
124 static int x_n=0;
125 static int y_n=0;
127 /* determines padding, etc. Will not expand the frame to prevent
128 overruns of user-set titles/legends */
129 void setup_graphs(int start_x_step,
130 int end_x_step, /* inclusive; not one past */
131 int x_major_d,
132 float x_major_f,
134 int start_y_step,
135 int end_y_step, /* inclusive; not one past */
136 int y_major_d,
137 float y_major_f,
139 int subtitles,
140 float fs){
142 /* determine ~ padding needed */
143 cairo_surface_t *cs=cairo_image_surface_create(CAIRO_FORMAT_RGB24,100,100);
144 cairo_t *ct=cairo_create(cs);
145 cairo_text_extents_t extents;
146 cairo_font_extents_t fextents;
147 int y;
149 fontsize=12;
150 leftpad=0;
151 rightpad=0;
152 toppad=0;
153 bottompad=0;
154 legendy=0;
155 legendh=0;
156 pic_w=0;
157 pic_h=0;
158 titleheight=0.;
160 x_n = end_x_step-start_x_step+1;
161 y_n = end_y_step-start_y_step+1;
162 fontsize=fs;
163 x0s=start_x_step;
164 x1s=end_x_step;
165 xmajor=x_major_d;
166 xmajorf=x_major_f;
167 y0s=start_y_step;
168 y1s=end_y_step;
169 ymajor=y_major_d;
170 ymajorf=y_major_f;
172 /* y labels */
173 cairo_set_font_size(ct, fontsize);
174 for(y=y0s+fontsize;y<=y1s;y++){
175 if(y%ymajor==0){
176 char buf[80];
177 snprintf(buf,80,"%.0f",(float)y/ymajor*ymajorf);
178 cairo_text_extents(ct, buf, &extents);
179 if(extents.width + extents.height*3.5>leftpad)leftpad=extents.width + extents.height*3.5;
183 /* x labels */
184 cairo_font_extents(ct, &fextents);
185 if(fextents.height*3>bottompad)bottompad=fextents.height*3;
187 /* center horizontally */
188 if(leftpad<rightpad)leftpad=rightpad;
189 if(rightpad<leftpad)rightpad=leftpad;
191 /* top legend */
193 float sofar=0;
194 cairo_save(ct);
195 cairo_select_font_face (ct, "",
196 CAIRO_FONT_SLANT_NORMAL,
197 CAIRO_FONT_WEIGHT_BOLD);
198 cairo_set_font_size(ct,fontsize*1.25);
199 cairo_font_extents(ct, &fextents);
200 sofar+=fextents.height;
201 cairo_restore(ct);
203 cairo_font_extents(ct, &fextents);
204 while(subtitles--)
205 sofar+=fextents.height;
206 if(sofar>titleheight)titleheight=sofar;
207 if(toppad<titleheight+fontsize*2)toppad=titleheight+fontsize*2;
210 /* color legend */
212 float width=0.;
213 float w1,w2,w3;
215 cairo_text_extents(ct, "100", &extents);
216 w1=extents.width*2*12;
217 cairo_text_extents(ct, ".000001", &extents);
218 w2=extents.width*1.5*7;
219 cairo_text_extents(ct, ".0001%", &extents);
220 w3=extents.width*1.5*7;
222 width+=MAX(w1,MAX(w2,w3));
224 legendy = y_n+extents.height*4;
225 legendh = extents.height*1.5;
227 if(legendy+legendh*4>bottompad)
228 bottompad=(legendy-y_n)+legendh*2.5;
231 pic_w = x_n + leftpad + rightpad;
232 pic_h = y_n + toppad + bottompad;
235 /* draws the page surrounding the graph data itself */
236 cairo_t *draw_page(char *title,
237 char *subtitle1,
238 char *subtitle2,
239 char *subtitle3,
240 char *xaxis_label,
241 char *yaxis_label,
242 char *legend_label,
243 int datatype,
244 int xdcp){
246 int i;
247 cairo_text_extents_t extents;
248 cairo_font_extents_t fextents;
249 cairo_surface_t *cs=cairo_image_surface_create(CAIRO_FORMAT_ARGB32,pic_w, pic_h);
250 if(!cs || cairo_surface_status(cs)!=CAIRO_STATUS_SUCCESS){
251 fprintf(stderr,"Could not set up Cairo surface.\n\n");
252 exit(1);
254 cairo_t *c = cairo_create(cs);
256 /* clear page to white */
257 cairo_set_source_rgb(c,1,1,1);
258 cairo_rectangle(c,0,0,pic_w,pic_h);
259 cairo_fill(c);
260 cairo_set_font_size(c, fontsize);
262 /* set graph area to transparent */
263 cairo_save(c);
264 cairo_set_source_rgba(c,0,0,0,0);
265 cairo_set_operator(c,CAIRO_OPERATOR_SOURCE);
266 cairo_rectangle(c,leftpad,toppad,x_n,y_n);
267 cairo_fill(c);
268 cairo_restore(c);
270 /* Y axis numeric labels */
271 cairo_set_source_rgb(c,0,0,0);
272 for(i=y0s+fontsize/2;i<=y1s;i++){
273 if(i%ymajor==0){
274 int y = toppad+y_n-i+y0s;
275 char buf[80];
277 snprintf(buf,80,"%.0f",(float)i/ymajor*ymajorf);
278 cairo_text_extents(c, buf, &extents);
279 cairo_move_to(c,leftpad - fontsize*.5 - extents.width,y+extents.height*.5);
280 cairo_show_text(c,buf);
284 /* X axis labels */
285 for(i=x0s;i<=x1s;i++){
286 if(i%xmajor==0){
287 char buf[80];
288 int x = leftpad + i - x0s;
289 if(i==0 && xdcp){
290 snprintf(buf,80,"DC");
291 }else{
292 snprintf(buf,80,"%.0f",(float)i/xmajor*xmajorf);
294 cairo_text_extents(c, buf, &extents);
295 cairo_move_to(c,x - extents.width/2,y_n+toppad+extents.height+fontsize*.5);
296 cairo_show_text(c,buf);
300 /* Y axis caption */
302 cairo_matrix_t a;
303 cairo_matrix_t b = {0.,-1., 1.,0., 0.,0.}; // account for border!
304 cairo_matrix_t d;
305 cairo_text_extents(c, yaxis_label, &extents);
306 cairo_move_to(c,extents.height+fontsize*.5,y_n/2+toppad+extents.width*.5);
308 cairo_save(c);
309 cairo_get_matrix(c,&a);
310 cairo_matrix_multiply(&d,&a,&b);
311 cairo_set_matrix(c,&d);
312 cairo_show_text(c,yaxis_label);
313 cairo_restore(c);
316 /* X axis caption */
318 cairo_text_extents(c, xaxis_label, &extents);
319 cairo_move_to(c,pic_w/2-extents.width/2,y_n+toppad+extents.height*2+fontsize*.25);
320 cairo_show_text(c,xaxis_label);
323 /* top title(s) */
325 float y = (toppad-titleheight);
326 if(title){
327 cairo_save(c);
328 cairo_select_font_face (c, "",
329 CAIRO_FONT_SLANT_NORMAL,
330 CAIRO_FONT_WEIGHT_BOLD);
331 cairo_set_font_size(c,fontsize*1.25);
332 cairo_font_extents(c, &fextents);
333 cairo_text_extents(c, title, &extents);
334 cairo_move_to(c,pic_w/2-extents.width/2,y);
335 cairo_show_text(c,title);
336 y+=fextents.height;
337 cairo_restore(c);
339 cairo_font_extents(c, &fextents);
340 if(subtitle1){
341 cairo_text_extents(c, subtitle1, &extents);
342 cairo_move_to(c,pic_w/2-extents.width/2,y);
343 cairo_show_text(c,subtitle1);
344 y+=fextents.height;
346 if(subtitle2){
347 cairo_text_extents(c, subtitle2, &extents);
348 cairo_move_to(c,pic_w/2-extents.width/2,y);
349 cairo_show_text(c,subtitle2);
350 y+=fextents.height;
352 if(subtitle3){
353 cairo_text_extents(c, subtitle3, &extents);
354 cairo_move_to(c,pic_w/2-extents.width/2,y);
355 cairo_show_text(c,subtitle3);
356 y+=fextents.height;
360 /* color legend */
362 float cw;
363 float ly;
364 cairo_text_extents(c, "100", &extents);
365 cw=extents.width*2*11;
366 cairo_text_extents(c, ".000001", &extents);
367 cw=MAX(cw,extents.width*1.5*7);
368 cairo_text_extents(c, ".0001%", &extents);
369 cw=MAX(cw,extents.width*1.5*7);
371 if(datatype==DT_iterations){
372 char buf[80];
373 int i;
374 float w=cw/11,px=leftpad+x_n;
376 for(i=0;i<=100;i++){
377 switch(i){
378 case 0:
379 case 1:
380 case 2:
381 case 3:
382 case 4:
383 case 5:
384 case 10:
385 case 20:
386 case 30:
387 case 40:
388 case 50:
389 case 100:
390 px-=w;
391 cairo_rectangle(c,px,legendy+toppad,w,legendh*1.25);
392 cairo_set_source_rgb(c,0,0,0);
393 cairo_stroke_preserve(c);
394 set_iter_color(c, i, 1.);
395 cairo_fill(c);
397 snprintf(buf,80,"%d",i);
398 cairo_text_extents(c, buf, &extents);
399 cairo_move_to(c,px+w/2-extents.width*.5,
400 ly=legendy+toppad+legendh*.625+extents.height/2);
401 set_iter_text_color(c, i);
402 cairo_show_text(c, buf);
404 break;
407 cairo_text_extents(c, legend_label, &extents);
408 cairo_move_to(c,px-extents.width-legendh*.75,ly);
409 cairo_show_text(c,legend_label);
410 }else{
411 int per_p = (datatype==DT_percent);
412 int i;
413 float w=cw/7,px=leftpad+x_n;
415 for(i=0;i<7;i++){
416 char *buf;
418 px-=w;
419 cairo_rectangle(c,px,legendy+toppad,w,legendh*1.25);
420 cairo_set_source_rgb(c,0,0,0);
421 cairo_stroke_preserve(c);
423 switch(i){
424 case 0:
425 buf=(per_p?".0001%":".000001");
426 set_error_color(c, 0., 1.);
427 cairo_fill(c);
428 set_error_text_color(c, 0.);
429 break;
430 case 1:
431 buf=(per_p?".001%":".00001");
432 set_error_color(c, .00001, 1.);
433 cairo_fill(c);
434 set_error_text_color(c, .00001);
435 break;
436 case 2:
437 buf=(per_p?".01%":".0001");
438 set_error_color(c, .0001, 1.);
439 cairo_fill(c);
440 set_error_text_color(c, .0001);
441 break;
442 case 3:
443 buf=(per_p?".1%":".001");
444 set_error_color(c, .001, 1.);
445 cairo_fill(c);
446 set_error_text_color(c, .001);
447 break;
448 case 4:
449 buf=(per_p?"1%":".01");
450 set_error_color(c, .01, 1.);
451 cairo_fill(c);
452 set_error_text_color(c, .01);
453 break;
454 case 5:
455 buf=(per_p?"10%":".1");
456 set_error_color(c, .1, 1.);
457 cairo_fill(c);
458 set_error_text_color(c, .1);
459 break;
460 case 6:
461 buf=(per_p?"100%":"1");
462 set_error_color(c, 1., 1.);
463 cairo_fill(c);
464 set_error_text_color(c, 1.);
465 break;
468 cairo_text_extents(c, buf, &extents);
469 cairo_move_to(c,px+w/2-extents.width*.5,
470 ly=legendy+toppad+legendh*.625+extents.height/2);
471 cairo_show_text(c,buf);
474 cairo_text_extents(c, legend_label, &extents);
475 cairo_move_to(c,px-extents.width-legendh*.75,ly);
476 cairo_show_text(c,legend_label);
480 return c;
483 void to_png(cairo_t *c,char *base, char *name){
484 if(c){
485 cairo_surface_t *cs=cairo_get_target(c);
486 char buf[320];
487 snprintf(buf,320,"%s-%s.png",base,name);
488 cairo_surface_write_to_png(cs,buf);
492 void destroy_page(cairo_t *c){
493 if(c){
494 cairo_surface_t *cs=cairo_get_target(c);
495 cairo_destroy(c);
496 cairo_surface_destroy(cs);