00001
00002
00003
00004
00005 #include <ALL.H>
00006 #include <COLOR.H>
00007 #include <OINFO.H>
00008 #include <OVGA.H>
00009 #include <OSYS.H>
00010 #include <OFONT.H>
00011 #include <OMOUSE.H>
00012 #include <OPIECHRT.H>
00013 #include <OIFACE.H>
00014
00015 #include <math.h>
00016
00017
00018
00019 #define MAX_LEN_LABEL "000"
00020
00021 static int default_series_color[] = {
00022 V_BLUE,
00023 V_GREEN,
00024 V_RED,
00025 V_YELLOW,
00026 V_VIOLET,
00027 V_BROWN,
00028 V_ORANGE,
00029 V_PINK,
00030 V_BLACK,
00031 V_WHITE,
00032 };
00033
00034 enum { DEFAULT_SERIES_COLOR_NUM = 10 };
00035
00036 enum {
00037 LEGEND_SIZE = 11,
00038 LEGEND_X_SPACING = 12,
00039 LEGEND_Y_SPACING = 2,
00040 };
00041
00042 enum { COMMON_OFFSET = 2 };
00043
00044
00045
00046
00047
00048
00050
00051 init_flag = 0;
00052 piechart_bitmap = NULL;
00053 }
00054
00055
00056
00057
00059
00060 deinit();
00061 }
00062
00063
00064
00065
00098
00099 void *dataArray, char dataTypeFlag,
00100 int *xStart, int *xEnd, char *xLabel, char *yLabel,
00101 char **legendArray, char transparentFlag,
00102 char orientationFlag, char valueFlag,
00103 int numFormat, int *seriesColor, int axisColor) {
00104 err_when(dataNum > DEFAULT_SERIES_COLOR_NUM && !seriesColor);
00105 err_when(dataNum <= 0);
00106 err_when(*xEnd < *xStart);
00107
00108 graph_width = x2 - x1 - 6;
00109
00110 err_when(graph_width < 0);
00111
00112 piechart_x1 = x1;
00113 piechart_y1 = y1;
00114 piechart_x2 = x2;
00115 piechart_y2 = y2;
00116
00117 centerx = (piechart_x1+piechart_x2)/2;
00118 centery = (piechart_y1+piechart_y2)/2;
00119 int radius1 = (piechart_x2-piechart_x1)/2-3*COMMON_OFFSET;
00120 int radius2 = (piechart_y2-piechart_y1)/2-3*COMMON_OFFSET;
00121 radius = (radius1>radius2)?radius2:radius1;
00122 series_num = dataNum;
00123 data_num = dataNum;
00124 data_array = dataArray;
00125 data_type_flag = dataTypeFlag;
00126 x_start = xStart;
00127 x_end = xEnd;
00128
00129 x_label = xLabel;
00130 y_label = yLabel;
00131 legend_array = legendArray;
00132
00133 transparent_flag = transparentFlag;
00134 orientation_flag = orientationFlag;
00135 value_flag = valueFlag;
00136 num_format = num_format;
00137
00138 series_color = seriesColor ? seriesColor : default_series_color;
00139 axis_color = axisColor;
00140
00141 init_flag = 1;
00142
00143 y_label_max_len = font_chartsm.text_width(MAX_LEN_LABEL);
00144 set_font(&font_chartsm);
00145
00146 }
00147
00148
00149
00150
00152
00153 if (piechart_bitmap) {
00154 mem_del(piechart_bitmap);
00155 piechart_bitmap = NULL;
00156 }
00157
00158 init_flag = 0;
00159 }
00160
00161
00162
00163
00165
00166 if (!init_flag)
00167 return;
00168
00169 font_ptr = fontPtr;
00170
00171 calc_pos();
00172 }
00173
00174
00175
00176
00181
00182 if (legend_array) {
00183 short textWidth = 0, textHeight = font_ptr->max_font_height;
00184
00185 for (int i = 0; i < series_num; i++) {
00186 if (font_ptr->text_width(legend_array[i]) > textWidth)
00187 textWidth = font_ptr->text_width(legend_array[i]);
00188 }
00189
00190 err_when(textWidth + LEGEND_X_SPACING * 2 > graph_width);
00191
00192 legend_x_num = (graph_width - LEGEND_X_SPACING*2) / (textWidth + LEGEND_X_SPACING*2);
00193 legend_y_num = (series_num / legend_x_num) + ((series_num % legend_x_num) ? 1 : 0);
00194
00195 graph_height = piechart_y2 - piechart_y1 - legend_y_num * (textHeight + LEGEND_Y_SPACING) - 6;
00196
00197 err_when(graph_height <= 0);
00198
00199 legend_width = (graph_width - LEGEND_X_SPACING*2) / legend_x_num;
00200 legend_height = textHeight + LEGEND_Y_SPACING;
00201 }
00202 else {
00203 legend_width = legend_height = legend_x_num = legend_y_num = 0;
00204 graph_height = piechart_y2 - piechart_y1 - 6;
00205 }
00206
00207 short YLabelWidth = y_label ? (orientation_flag ? font_ptr->max_font_height : font_ptr->text_width(y_label)) : -COMMON_OFFSET;
00208 short XLabelHeight = x_label ? (font_ptr->max_font_height) : -COMMON_OFFSET;
00209 series_x1 = piechart_x1 + 4 + COMMON_OFFSET*4 + YLabelWidth + y_label_max_len;
00210 series_y1 = piechart_y1 + 4 + COMMON_OFFSET*6;
00211 series_x2 = piechart_x2 - 4 - COMMON_OFFSET*12;
00212 series_y2 = piechart_y1 + graph_height - COMMON_OFFSET*3 - (font_ptr->max_font_height) - XLabelHeight;
00213 }
00214
00215
00216
00217
00219
00220 if (transparent_flag) {
00221 user_interface.brighten(piechart_x1+4, piechart_y1+4, piechart_x2-2, piechart_y2-2);
00222 piechart_bitmap = vga_back.save_area(piechart_x1+4, piechart_y1+4, piechart_x2-2, piechart_y2-2, piechart_bitmap);
00223 }
00224
00225
00226 refresh();
00227 }
00228
00229
00230
00231
00233
00234
00235
00236 if (transparent_flag) {
00237 user_interface.rect(piechart_x1, piechart_y1, piechart_x2, piechart_y2, 1);
00238 vga_back.rest_area(piechart_bitmap, 0, 0);
00239 }
00240 else {
00241 user_interface.bar(piechart_x1, piechart_y1, piechart_x2, piechart_y2);
00242 user_interface.panel(piechart_x1+3, piechart_y1+3, piechart_x2-4, piechart_y2-4);
00243 }
00244 draw_series();
00245
00246
00247
00248
00249
00250
00251 }
00252
00253
00254
00255
00257
00258 for (int i = 0; i < series_num; i++) {
00259 short legendX = piechart_x1 + 4 + (i % legend_x_num) * legend_width + LEGEND_X_SPACING;
00260 short legendY = piechart_y1 + 4 + graph_height + (i / legend_x_num) * legend_height;
00261 user_interface.bar( legendX+LEGEND_X_SPACING, legendY+LEGEND_Y_SPACING,
00262 legendX+LEGEND_X_SPACING+LEGEND_SIZE, legendY+LEGEND_Y_SPACING+LEGEND_SIZE,
00263 series_color[i] );
00264 font_ptr->put( legendX+LEGEND_X_SPACING*2+LEGEND_SIZE, legendY+LEGEND_Y_SPACING, legend_array[i] );
00265 }
00266 }
00267
00268
00269
00270
00272
00273 short textHeight = font_ptr->max_font_height;
00274
00275 if (x_label) {
00276 font_ptr->center_put( series_x1, series_y2+COMMON_OFFSET*2+textHeight,
00277 series_x2, piechart_y1+graph_height-COMMON_OFFSET, x_label );
00278 }
00279
00280 if (y_label) {
00281 short textWidth = font_ptr->text_width(y_label) + 1;
00282
00283 if (orientation_flag) {
00284 short *fontBuf = (short *) sys.common_data_buf;
00285 err_when(textWidth * textHeight * sizeof(short) > COMMON_DATA_BUF_SIZE);
00286
00287 for (int i = 0; i < textWidth * textHeight; i++)
00288 *fontBuf++ = transparent_code_w;
00289
00290 font_ptr->put_to_bufferW(fontBuf = (short *) sys.common_data_buf, textWidth * sizeof(short), 0, 0, y_label);
00291
00292 short xStart = piechart_x1 + 4 + COMMON_OFFSET * 2;
00293 short yStart = (series_y1 + series_y2 - textWidth) / 2;
00294
00295 for (short x = 0; x < textHeight; x++) {
00296 for (short y = textWidth - 1; y >= 0; y--, fontBuf++) {
00297 if (*fontBuf != transparent_code_w)
00298 *vga_back.buf_ptr(xStart+x, yStart+y) = *fontBuf;
00299 }
00300 }
00301 }
00302 else {
00303 font_ptr->center_put( piechart_x1+4+COMMON_OFFSET*2, series_y1,
00304 piechart_x1+4+COMMON_OFFSET*2+textWidth, series_y2, y_label);
00305 }
00306 }
00307 }
00308
00309
00310
00311
00313
00314 double data, maxVal = 0.0;
00315 x_axis_pos = 0;
00316
00317 for (int i = 0; i < series_num * data_num; i++) {
00318 switch (data_type_flag) {
00319 case DATA_DOUBLE:
00320 data = ((double*)data_array)[i];
00321 break;
00322 case DATA_FLOAT:
00323 data = double(((float*)data_array)[i]);
00324 break;
00325 case DATA_INT:
00326 data = double(((int*)data_array)[i]);
00327 break;
00328 case DATA_LONG:
00329 data = double(((long*)data_array)[i]);
00330 break;
00331 }
00332 if (fabs(data) > maxVal)
00333 maxVal = fabs(data);
00334 if (!x_axis_pos && data < 0.0)
00335 x_axis_pos = 1;
00336 }
00337 if (maxVal>0)
00338 max_scale = pow(10,ceil(log10(maxVal)));
00339 else
00340 max_scale = 5;
00341 }
00342
00343
00344
00345
00347
00348 find_scale();
00349
00350 short xAxisPos;
00351
00352
00353
00354 if (x_axis_pos)
00355 vga_back.bar(series_x1, series_y1-COMMON_OFFSET*2, series_x1+1, series_y2+COMMON_OFFSET*2, axis_color);
00356 else
00357 vga_back.bar(series_x1, series_y1-COMMON_OFFSET*2, series_x1+1, series_y2, axis_color);
00358
00359 short scaleNum = (series_y2-series_y1-font_ptr->max_font_height) / (font_ptr->max_font_height*3/2);
00360 if ( scaleNum > 0 )
00361 scaleNum = short(pow(2,floor(log10(double(scaleNum))/log10(2.0))));
00362 else
00363 scaleNum = 0;
00364 short scaleStep = (series_y2-series_y1) / scaleNum;
00365 double scaleValue;
00366 for (int i = 0; i <= scaleNum; i++) {
00367 if ( (x_axis_pos && i == scaleNum / 2) || !(x_axis_pos || i) )
00368 vga_back.bar(series_x1, xAxisPos=series_y2-i*scaleStep-1, series_x2+COMMON_OFFSET*8, series_y2-i*scaleStep, axis_color);
00369 else
00370 vga_back.bar(series_x1, series_y2-i*scaleStep, series_x1+COMMON_OFFSET*2, series_y2-i*scaleStep, axis_color);
00371
00372 if (x_axis_pos)
00373 scaleValue = max_scale*2/scaleNum*i - max_scale;
00374 else
00375 scaleValue = max_scale/scaleNum*i;
00376
00377 switch (data_type_flag) {
00378 case DATA_FLOAT:
00379 case DATA_DOUBLE:
00380 font_ptr->right_put(series_x1-COMMON_OFFSET, series_y2-i*scaleStep-font_ptr->max_font_height/2, m.format(scaleValue,num_format));
00381 break;
00382 case DATA_INT:
00383 case DATA_LONG:
00384 font_ptr->right_put(series_x1-COMMON_OFFSET, series_y2-i*scaleStep-font_ptr->max_font_height/2, m.format(long(scaleValue),num_format));
00385 }
00386 }
00387
00388
00389
00390 short maxLabelWidth = font_ptr->text_width(m.format(*x_end, 4))+COMMON_OFFSET*2;
00391 x_axis_step = (series_x2-series_x1) / (data_num-1);
00392 short displayInc = 1;
00393 while (displayInc * x_axis_step / maxLabelWidth < 1) displayInc++;
00394 int xAxisStep = (*x_end - *x_start) / (data_num - 1);
00395 for (i = 0; i < data_num-1; i += displayInc) {
00396 vga_back.bar(series_x2-i*x_axis_step, xAxisPos-COMMON_OFFSET*2, series_x2-i*x_axis_step, xAxisPos, axis_color);
00397 font_ptr->center_put((series_x2-i*x_axis_step)-maxLabelWidth/2-COMMON_OFFSET, xAxisPos+COMMON_OFFSET,
00398 (series_x2-i*x_axis_step)+maxLabelWidth/2+COMMON_OFFSET, xAxisPos+COMMON_OFFSET+font_ptr->max_font_height, m.format(*x_end-xAxisStep*i, 4));
00399 }
00400 }
00401
00402
00403
00404
00406
00407 switch (data_type_flag) {
00408 case DATA_FLOAT: draw_series_float(); break;
00409 case DATA_DOUBLE: draw_series_double(); break;
00410 case DATA_INT: draw_series_int(); break;
00411 case DATA_LONG: draw_series_long(); break;
00412 }
00413 }
00414
00415
00416
00417
00419
00420
00421 double t1=theta1, t2=theta2;
00422 double sint3,cost3,t3,t4,t5,x,y;
00423 double skip=1.0;
00424
00425 if(theta1==theta2)return;
00426
00427 t3=0.5*(t1+t2);
00428 sint3=sin(t3);
00429 cost3=cos(t3);
00430 t4=2*(skip/(t2-t1));
00431 t5=skip/radius;
00432 x=centerx;
00433 y=centery;
00434 while(t1<=t2) {
00435 vga_back.thick_line(
00436 (int)x, (int)y, centerx+(int)(radius*cos(t1)), centery+(int)(radius*sin(t1)),
00437 vga_back.translate_color(series_color[piecolor]));
00438 vga_back.thick_line(
00439 (int)x, (int)y, centerx+(int)(radius*cos(t2)), centery+(int)(radius*sin(t2)),
00440 vga_back.translate_color(series_color[piecolor]));
00441
00442 x+=t4*cost3;
00443 y+=t4*sint3;
00444 t1+=t5;
00445 t2-=t5;
00446 }
00447 t1=theta1;
00448 t2=theta2;
00449 while(t1<=t2) {
00450 vga_back.thick_line(
00451 centerx+(int)(radius*cos(t2)), centery+(int)(radius*sin(t2)),
00452 centerx+(int)(radius*cos(t2-=t5)), centery+(int)(radius*sin(t2)),
00453 vga_back.translate_color(V_GRAY-5));
00454 vga_back.thick_line(
00455 centerx+(int)(radius*cos(t1)), centery+(int)(radius*sin(t1)),
00456 centerx+(int)(radius*cos(t1+=t5)), centery+(int)(radius*sin(t1)),
00457 vga_back.translate_color(V_GRAY-5));
00458 x+=t4*cost3;
00459 y+=t4*sint3;
00460 }
00461
00462 }
00463
00464
00465
00466
00468
00469 int *dataArray = (int *) data_array;
00470 long total=0;
00471 double theta1,theta2;
00472
00473 for (int i = 0; i < data_num; i++)
00474 total+=(long)(dataArray[i]);
00475
00476 if(total<1E-9)total=1;
00477 theta2=0.0;
00478 for (i = 0; i < data_num; i++) {
00479 theta1=theta2;
00480 theta2+=6.2832*(double)dataArray[i]/total;
00481 draw_pie(theta1,theta2,i);
00482
00483 if((theta1!=theta2)
00484 &&(fabs(theta2-theta1-6.2832)>1e-9)) {
00485 vga_back.thick_line(
00486 centerx,
00487 centery,
00488 centerx+(int)(radius*cos(theta1)),
00489 centery+(int)(radius*sin(theta1)),
00490 vga_back.translate_color(V_GRAY-5));
00491 vga_back.thick_line(
00492 centerx,
00493 centery,
00494 centerx+(int)(radius*cos(theta2)),
00495 centery+(int)(radius*sin(theta2)),
00496 vga_back.translate_color(V_GRAY-5));
00497 }
00498 }
00499
00500 }
00501
00502
00503
00504 void PieChart::draw_series_long() {
00505 long *dataArray = (long *) data_array;
00506 long total=0;
00507 double theta1,theta2;
00508
00509 for (int i = 0; i < data_num; i++)
00510 total+=(long)(dataArray[i]);
00511 if(total<1E-9)total=1;
00512
00513 theta2=0.0;
00514 for (i = 0; i < data_num; i++) {
00515 theta1=theta2;
00516 theta2+=6.2832*(double)dataArray[i]/total;
00517 draw_pie(theta1,theta2,i);
00518 }
00519 theta1=0.0;
00520 for (i = 0; i <= data_num; i++) {
00521 vga_back.thick_line(
00522 centerx, centery,
00523 centerx+(int)(radius*cos(theta1)), centery+(int)(radius*sin(theta1)),
00524 vga_back.translate_color(V_GRAY-5));
00525 theta1+=6.2832*(double)dataArray[i]/total;
00526 }
00527 }
00528
00529
00530
00531
00532
00533 void PieChart::draw_series_float() {
00534 float *dataArray = (float *) data_array;
00535 float total=0;
00536 double theta1,theta2;
00537
00538 for (int i = 0; i < data_num; i++)
00539 total+=(float)(dataArray[i]);
00540
00541 if(total<1E-9)total=1;
00542
00543 theta2=0.0;
00544 for (i = 0; i < data_num; i++) {
00545 theta1=theta2;
00546 theta2+=6.2832*(double)dataArray[i]/total;
00547 draw_pie(theta1,theta2,i);
00548 }
00549 theta1=0.0;
00550 for (i = 0; i <= data_num; i++) {
00551 vga_back.thick_line(
00552 centerx, centery,
00553 centerx+(int)(radius*cos(theta1)), centery+(int)(radius*sin(theta1)),
00554 vga_back.translate_color(V_GRAY-5));
00555 theta1+=6.2832*(double)dataArray[i]/total;
00556 }
00557
00558 }
00559
00560
00561
00562
00563
00564 void PieChart::draw_series_double() {
00565 double *dataArray = (double *) data_array;
00566 double total=0;
00567 double theta1,theta2;
00568
00569 for (int i = 0; i < data_num; i++)
00570 total+=(double)(dataArray[i]);
00571
00572 if(total<1E-9)total=1;
00573
00574 theta2=0.0;
00575 for (i = 0; i < data_num; i++) {
00576 theta1=theta2;
00577 theta2+=6.2832*(double)dataArray[i]/total;
00578 draw_pie(theta1,theta2,i);
00579 }
00580
00581 theta1=0.0;
00582 for (i = 0; i <= data_num; i++) {
00583 vga_back.thick_line(
00584 centerx, centery,
00585 centerx+(int)(radius*cos(theta1)), centery+(int)(radius*sin(theta1)),
00586 vga_back.translate_color(V_GRAY-5));
00587 theta1+=6.2832*(double)dataArray[i]/total;
00588 }
00589
00590 }
00591
00592
00593
00594
00596
00597 char *valueString;
00598 switch (data_type_flag) {
00599 case DATA_FLOAT:
00600 valueString = m.format(*((float *) value), num_format); break;
00601 case DATA_DOUBLE:
00602 valueString = m.format(*((double *) value), num_format); break;
00603 case DATA_INT:
00604 valueString = m.format(*((int *) value), num_format); break;
00605 case DATA_LONG:
00606 valueString = m.format(*((long *) value), num_format); break;
00607 }
00608
00609 short textHeight = font_ptr->max_font_height;
00610 short textWidth = font_ptr->text_width(valueString) + 1;
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630 font_chartsm.put(x+3,y,valueString);
00631 }
00632
00633