192ceb2003-11-22Henrik Grubbström (Grubba) //! Graph sub-module for drawing pie-charts.
2249372001-11-19Martin Nilsson // // These functions were written by Henrik "Hedda" Wallin (hedda@roxen.com) // Create_pie can draw pie charts in different forms.
d697d71999-09-30Henrik Wallin 
a580e12000-09-27Fredrik Hübinette (Hubbe) #pike __REAL_VERSION__
a20af62000-09-26Fredrik Hübinette (Hubbe) 
d697d71999-09-30Henrik Wallin #include "graph.h"
78ee8b2005-11-15Martin Nilsson inherit .create_bars;
d697d71999-09-30Henrik Wallin  mapping(string:mixed) create_pie(mapping(string:mixed) diagram_data) { //Only tested with xsize>=100
e27f9e2005-11-15Martin Nilsson  int si=diagram_data->fontsize;
d697d71999-09-30Henrik Wallin 
e1767a2005-11-14Martin Nilsson  Image.Image piediagram;
d697d71999-09-30Henrik Wallin  init_bg(diagram_data);
e27f9e2005-11-15Martin Nilsson  piediagram=diagram_data->image;
d697d71999-09-30Henrik Wallin  setinitcolors(diagram_data); set_legend_size(diagram_data);
e27f9e2005-11-15Martin Nilsson  diagram_data->ysize-=diagram_data->legend_size;
d697d71999-09-30Henrik Wallin  //Do the standard init (The init function is in create_graph) init(diagram_data); //Initiate values
faac082005-11-15Martin Nilsson  int size=diagram_data->xsize;
e27f9e2005-11-15Martin Nilsson  array(int|float) numbers=diagram_data->data[0];
faac082005-11-15Martin Nilsson  array(string) names=diagram_data->xnames; int twoD=diagram_data->drawtype=="2D"; array(array(int)) colors=diagram_data->datacolors; array(int) bg=diagram_data->bgcolor; array(int) fg=diagram_data->textcolor;
e27f9e2005-11-15Martin Nilsson  int tone=diagram_data->tone;
d697d71999-09-30Henrik Wallin  for(int i; i<sizeof(numbers); i++) if ((float)numbers[i]<0.0) numbers[i]*=-1.0;
faac082005-11-15Martin Nilsson 
d697d71999-09-30Henrik Wallin  //////////////////////
3524712015-05-26Martin Nilsson 
a3c9302000-08-28Henrik Wallin  array(object) text;
d697d71999-09-30Henrik Wallin  object notext; int ymaxtext; int xmaxtext; int imysize; int imxsize;
a3c9302000-08-28Henrik Wallin  array(float) arr=allocate(802); array(float) arr2=allocate(802); array(float) arr3=allocate(802); array(float) arrplus=allocate(802); array(float) arrpp=allocate(802);
d697d71999-09-30Henrik Wallin  int yc; int xc; int xr; int yr; mixed sum; int sum2;
a3c9302000-08-28Henrik Wallin  array(int) pnumbers=allocate(sizeof(numbers)); array(int) order=indices(numbers);
d697d71999-09-30Henrik Wallin  int edge_nr=0; //create the text objects if (names) text=allocate(sizeof(names));
3524712015-05-26Martin Nilsson 
e27f9e2005-11-15Martin Nilsson  if (diagram_data["3Ddepth"]>diagram_data->ysize/5) diagram_data["3Ddepth"]=diagram_data->ysize/5;
3524712015-05-26Martin Nilsson 
b122a72000-10-12Martin Nilsson  notext=GETFONT(xnamesfont);
d697d71999-09-30Henrik Wallin  if (names) if (notext) for(int i=0; i<sizeof(names); i++) { if ((names[i]!=0) && (names[i]!="")) text[i]=notext
e27f9e2005-11-15Martin Nilsson  ->write(UNICODE((string)(names[i]),diagram_data->encoding)) ->scale(0,diagram_data->fontsize);
d697d71999-09-30Henrik Wallin  else
e27f9e2005-11-15Martin Nilsson  text[i]=Image.Image(diagram_data->fontsize, diagram_data->fontsize);
d697d71999-09-30Henrik Wallin  if (text[i]->xsize()<1)
e27f9e2005-11-15Martin Nilsson  text[i]=Image.Image(diagram_data->fontsize, diagram_data->fontsize);
d697d71999-09-30Henrik Wallin 
e27f9e2005-11-15Martin Nilsson  if (text[i]->xsize()>diagram_data->xsize/5+diagram_data["3Ddepth"]) text[i]=text[i]->scale((int)diagram_data->xsize/5, 0);
d697d71999-09-30Henrik Wallin 
e27f9e2005-11-15Martin Nilsson  if (text[i]->ysize()>diagram_data->ysize/5-diagram_data["3Ddepth"]) text[i]=text[i]->scale(0, (int)diagram_data->ysize/5-
d697d71999-09-30Henrik Wallin  diagram_data["3Ddepth"]);
3524712015-05-26Martin Nilsson 
d697d71999-09-30Henrik Wallin  if (xmaxtext<(text[i]->xsize())) xmaxtext=text[i]->xsize(); if (ymaxtext<(text[i]->ysize())) ymaxtext=text[i]->ysize();
3524712015-05-26Martin Nilsson 
d697d71999-09-30Henrik Wallin  } else
484a742002-03-09Martin Nilsson  error("Missing font or similar error!\n");
d697d71999-09-30Henrik Wallin  int nameheight=write_name(diagram_data); //Some calculations if (twoD) {
e27f9e2005-11-15Martin Nilsson  xc=diagram_data->xsize/2; yc=diagram_data->ysize/2+nameheight/2;
3524712015-05-26Martin Nilsson  xr=(int)min(xc-xmaxtext-ymaxtext-1-diagram_data->linewidth,
d697d71999-09-30Henrik Wallin  yc-2*ymaxtext-
e27f9e2005-11-15Martin Nilsson  1-diagram_data->linewidth-nameheight);
d697d71999-09-30Henrik Wallin  yr=xr; } else {
e27f9e2005-11-15Martin Nilsson  xc=diagram_data->xsize/2; yc=diagram_data->ysize/2-diagram_data["3Ddepth"]/2+nameheight/2;
3524712015-05-26Martin Nilsson  yr=(int)(min(xc-xmaxtext-ymaxtext-1-diagram_data["3Ddepth"]/2,
d697d71999-09-30Henrik Wallin  yc-2*ymaxtext-1-nameheight)
e27f9e2005-11-15Martin Nilsson  -diagram_data->linewidth);
3524712015-05-26Martin Nilsson  xr=(int)(min(xc-xmaxtext-ymaxtext-1,
d697d71999-09-30Henrik Wallin  yc+diagram_data["3Ddepth"]/2- 2*ymaxtext-1-nameheight)-
e27f9e2005-11-15Martin Nilsson  diagram_data->linewidth);
d697d71999-09-30Henrik Wallin  }
e27f9e2005-11-15Martin Nilsson  float w=diagram_data->linewidth;
d697d71999-09-30Henrik Wallin  if (xr<2)
484a742002-03-09Martin Nilsson  error("Image to small for this pie-diagram.\n" "Try smaller font or bigger image!\n");
d697d71999-09-30Henrik Wallin  //initiate the 0.25*% for different numbers:
3524712015-05-26Martin Nilsson  //Ex: If numbers is ({3,3}) pnumbers will be ({200, 200})
d697d71999-09-30Henrik Wallin  sum=`+(@ numbers); int i; if (sum>LITET) { for(int i=0; i<sizeof(numbers); i++) { float t=(float)(numbers[i]*400)/sum; pnumbers[i]=(int)floor(t); numbers[i]=t-floor(t); }
3524712015-05-26Martin Nilsson 
d697d71999-09-30Henrik Wallin  //Now the rests are in the numbers-array //We now make sure that the sum of pnumbers is 400. sort(numbers, order); sum2=`+(@ pnumbers); i=sizeof(pnumbers); while(sum2<400) { pnumbers[order[--i]]++; sum2++;
3524712015-05-26Martin Nilsson  }
d697d71999-09-30Henrik Wallin  } else if (sizeof(numbers)>1) { for(int i=0; i<sizeof(numbers); i++) pnumbers[i]=(int)floor(400.0/(float)sizeof(numbers)); int j=400-`+(@pnumbers); for(int i=0; i<j; i++) pnumbers[i]++; } else pnumbers=({400});
3524712015-05-26Martin Nilsson 
d697d71999-09-30Henrik Wallin  //Initiate the piediagram! float FI=0;
e27f9e2005-11-15Martin Nilsson  if (diagram_data->center)
d697d71999-09-30Henrik Wallin  {
3524712015-05-26Martin Nilsson  //If to great center integer is given, module is used.
d697d71999-09-30Henrik Wallin  // Center should not be greater than sizeof(data[0]).
e27f9e2005-11-15Martin Nilsson  diagram_data->center%=(1+sizeof(numbers)); FI=(400-`+(0,@pnumbers[0..diagram_data->center-2]) -pnumbers[diagram_data->center-1]*0.5)*2.0*PI/400.0;
d697d71999-09-30Henrik Wallin  } else
e27f9e2005-11-15Martin Nilsson  if (diagram_data->rotate) FI=((float)(diagram_data->rotate)*2.0*PI/360.0)%(2*PI);
d697d71999-09-30Henrik Wallin  float most_down=yc+yr+w; float most_right=xc+xr+w; float most_left=xc-xr-w; for(int i=0; i<401; i++) { arr[2*i]=xc+xr*sin((i*2.0*PI/400.0)+FI); arr[1+2*i]=yc+yr*sin(-PI/2+i*2.0*PI/400.0+FI); arr2[2*i]=xc+(xr+w)*sin((i*2.0*PI/400.0)); arr2[2*i+1]=yc+(w+yr)*sin(-PI/2+i*2.0*PI/400.0); arr3[2*i]=xc+(xr+w)*sin((-i*2.0*PI/400.0+FI)); arr3[2*i+1]=yc+(w+yr)*sin(-PI/2-i*2.0*PI/400.0+FI); } //Draw the slices
e27f9e2005-11-15Martin Nilsson  if (sizeof(diagram_data->datacolors)> sizeof(diagram_data->data[0])) diagram_data->datacolors=diagram_data->datacolors
8a531a2006-11-04Martin Nilsson  [..sizeof(diagram_data->data[0])-1];
3524712015-05-26Martin Nilsson 
e27f9e2005-11-15Martin Nilsson  int t=sizeof(diagram_data->datacolors);
d697d71999-09-30Henrik Wallin  float miniwxr; float miniwyr; if (!twoD) { array arrfoo=copy_value(arr2); miniwxr=max((w+xr)/2,(w+xr)-diagram_data["3Ddepth"]/10); miniwyr=max((w+yr)/2,(w+yr)-diagram_data["3Ddepth"]/10); for(int i=200; i<604; i+=2) { arrfoo[i]=xc+miniwxr*sin((i*PI/400.0)); arrfoo[i+1]=yc+miniwyr*sin(-PI/2+i*PI/400.0)+ diagram_data["3Ddepth"]; } //arrfoo[i]=arr2[i]+diagram_data["3Ddepth"]; for(int i=0; i<401; i++) { arrplus[2*i]=xc+(xr+w)*sin((i*2.0*PI/400.0)+FI); arrplus[1+2*i]=yc+(w+yr)*sin(-PI/2+i*2.0*PI/400.0+FI); arrpp[2*i]=xc+miniwxr*sin((-i*2.0*PI/400.0)+FI); arrpp[1+2*i]=yc+miniwyr*sin(-PI/2-i*2.0*PI/400.0+FI)+ diagram_data["3Ddepth"]; } object skugg;
e1767a2005-11-14Martin Nilsson  skugg=Image.Image(piediagram->xsize(),piediagram->ysize(), 255,255,255);
d697d71999-09-30Henrik Wallin  object foo;
e1767a2005-11-14Martin Nilsson  foo=Image.Image(piediagram->xsize(),piediagram->ysize(), 255,255,255);
3524712015-05-26Martin Nilsson  skugg->tuned_box(xc,yc-yr-1,xc+xr+1,1+yc+yr+diagram_data["3Ddepth"], ({
d697d71999-09-30Henrik Wallin  ({255,255,255}), ({100,100,100}), ({255,255,255}),
3524712015-05-26Martin Nilsson  ({100,100,100})
d697d71999-09-30Henrik Wallin  }));
3524712015-05-26Martin Nilsson  skugg->tuned_box(xc-xr-1,yc-yr-1,xc,1+yc+yr+diagram_data["3Ddepth"], ({
d697d71999-09-30Henrik Wallin  ({100,100,100}), ({255,255,255}), ({100,100,100}), ({255,255,255}) })); skugg->polyfill(arr2[600..801]+({xc,0,0,0})); skugg->polyfill( arr2[..201] + ({piediagram->xsize()-1,0,xc,0}) ); skugg->polyfill( arr2[200..201]+ arrfoo[200..401] + ({xc,piediagram->ysize()-1, piediagram->xsize()-1,piediagram->ysize()-1}) ); skugg->polyfill( arrfoo[400..601]+ arr2[600..601]+ ({0,piediagram->ysize()-1,xc,piediagram->ysize()-1 }) );
3524712015-05-26Martin Nilsson 
d697d71999-09-30Henrik Wallin  edge_nr=0; for(i=0; i<t; i++) { piediagram->setcolor(
e27f9e2005-11-15Martin Nilsson  @diagram_data->datacolors[i]
d697d71999-09-30Henrik Wallin  );
3524712015-05-26Martin Nilsson 
d697d71999-09-30Henrik Wallin  if (pnumbers[i]) { piediagram-> polygone( (arrplus[2*edge_nr..2*(edge_nr+pnumbers[i]+2)+1] + arrpp[800-2*(edge_nr+pnumbers[i]+2).. 801-2*edge_nr]) ); } edge_nr+=pnumbers[i]; } piediagram=piediagram*skugg; piediagram->setcolor(0,0,0); piediagram->polyfill(
e27f9e2005-11-15Martin Nilsson  make_polygon_from_line(diagram_data->linewidth,
d697d71999-09-30Henrik Wallin  ({
3524712015-05-26Martin Nilsson  xc+(xr+w/2.0),
d697d71999-09-30Henrik Wallin  yc})+ arrfoo[200.. 601]+
3524712015-05-26Martin Nilsson  ({xc-(xr+w/2.0),
d697d71999-09-30Henrik Wallin  yc}), 0,1)[0]); }
3524712015-05-26Martin Nilsson 
d697d71999-09-30Henrik Wallin  edge_nr=0; for(i=0; i<t; i++) {
e27f9e2005-11-15Martin Nilsson  piediagram=piediagram->setcolor(@diagram_data->datacolors[i]);
d697d71999-09-30Henrik Wallin  if (pnumbers[i]) piediagram=piediagram->polyfill(({(float)xc,(float)yc})+ arr[2*edge_nr..2*(edge_nr+pnumbers[i]+2)+1]); edge_nr+=pnumbers[i]; }
3524712015-05-26Martin Nilsson 
d697d71999-09-30Henrik Wallin  edge_nr=pnumbers[0]; //black borders
e27f9e2005-11-15Martin Nilsson  if (diagram_data->linewidth>LITET)
d697d71999-09-30Henrik Wallin  {
e27f9e2005-11-15Martin Nilsson  piediagram->setcolor(@diagram_data->axcolor);
d697d71999-09-30Henrik Wallin  piediagram->polygone(
e27f9e2005-11-15Martin Nilsson  make_polygon_from_line(diagram_data->linewidth,
d697d71999-09-30Henrik Wallin  ({ xc, yc, arr[0], arr[1] }) , 0, 1)[0] ); for(int i=1; i<sizeof(pnumbers); i++) { piediagram-> polygone(
e27f9e2005-11-15Martin Nilsson  make_polygon_from_line(diagram_data->linewidth,
d697d71999-09-30Henrik Wallin  ({xc ,yc, arr[2*(edge_nr)], arr[2*(edge_nr)+1] }) , 0, 1)[0] );
3524712015-05-26Martin Nilsson 
d697d71999-09-30Henrik Wallin  edge_nr+=pnumbers[i]; } piediagram->polygone(arr[..401] +arr3[400..]); piediagram->polygone(arr[400..] +arr3[..401]); }
3524712015-05-26Martin Nilsson 
d697d71999-09-30Henrik Wallin  piediagram->setcolor(255,255,255);
3524712015-05-26Martin Nilsson 
d697d71999-09-30Henrik Wallin  //And now some shading! if (!twoD) {
a3c9302000-08-28Henrik Wallin  array(int) b=({70,70,70}); array(int) a=({0,0,0});
3524712015-05-26Martin Nilsson 
d697d71999-09-30Henrik Wallin  object tbild;
e27f9e2005-11-15Martin Nilsson  int imxsize=piediagram->xsize(); //diagram_data->xsize; int imysize=piediagram->ysize(); //diagram_data->ysize+diagram_data->legendsize;
d697d71999-09-30Henrik Wallin  if(tone) {
3524712015-05-26Martin Nilsson 
e1767a2005-11-14Martin Nilsson  tbild=Image.Image(imxsize, imysize, 255, 255, 255)->
d697d71999-09-30Henrik Wallin  tuned_box(0, 0 , 1, imysize, ({a,a,b,b})); tbild=tbild->paste(tbild->copy(0,0,0, imysize), 1, 0); tbild=tbild->paste(tbild->copy(0,0,1, imysize), 2, 0); tbild=tbild->paste(tbild->copy(0,0,3, imysize), 4, 0); tbild=tbild->paste(tbild->copy(0,0,7, imysize), 8, 0); tbild=tbild->paste(tbild->copy(0,0,15, imysize), 16, 0); if (imxsize>32) tbild=tbild->paste(tbild->copy(0,0,31, imysize), 32, 0);
3524712015-05-26Martin Nilsson 
d697d71999-09-30Henrik Wallin  if (imxsize>64) tbild-> paste(tbild->copy(0,0,63, imysize), 64, 0); if (imxsize>128) tbild=tbild->paste(tbild->copy(0,0,128, imysize), 128, 0); if (imxsize>256) tbild=tbild->paste(tbild->copy(0,0,256, imysize), 256, 0); if (imxsize>512) tbild=tbild->paste(tbild->copy(0,0,512, imysize), 512, 0); piediagram+=tbild; } //Vertical lines below edge_nr=(int)(FI*200.0/PI+0.5); piediagram->setcolor(0,0,0); for(int i=0; i<sizeof(pnumbers); i++) { if (sin(-PI/2+edge_nr*2.0*PI/400.0)>0) {
3524712015-05-26Martin Nilsson 
d697d71999-09-30Henrik Wallin  float x1=xc+(xr+w/2.0)*sin((edge_nr*2.0*PI/400.0)); float y1=yc+(w/2.0+yr)*sin(-PI/2+edge_nr*2.0*PI/400.0); float x2=xc+(miniwxr-w/2.0)*sin((edge_nr*2.0*PI/400.0)); float y2=yc+diagram_data["3Ddepth"] +(miniwyr-w/2.0)*sin(-PI/2+edge_nr*2.0*PI/400.0); piediagram=piediagram-> polygone(
e27f9e2005-11-15Martin Nilsson  make_polygon_from_line(diagram_data->linewidth,
d697d71999-09-30Henrik Wallin  ({ x1,y1, x2,y2 }) , 0, 1)[0] );
3524712015-05-26Martin Nilsson 
d697d71999-09-30Henrik Wallin  } edge_nr+=pnumbers[i]; }
3524712015-05-26Martin Nilsson 
d697d71999-09-30Henrik Wallin  }
3524712015-05-26Martin Nilsson 
d697d71999-09-30Henrik Wallin  //write the text! int|float place; sum=0; if (names) for(int i=0; i<min(sizeof(pnumbers), sizeof(text)); i++) { int t; sum+=pnumbers[i]; place=sum-pnumbers[i]/2; if (FI) { place=place+FI*400.0/(2.0*PI); if (place>400) place=place%400; } piediagram=piediagram->setcolor(255,0, 0);
3524712015-05-26Martin Nilsson 
d697d71999-09-30Henrik Wallin  t=(place<202)?0:-text[i]->xsize(); int yt=0; if (((place>100)&&(place<300))&& (!twoD)) yt=diagram_data["3Ddepth"];
3524712015-05-26Martin Nilsson 
d697d71999-09-30Henrik Wallin  int ex=text[i]->ysize(); int x=(int)(xc +t+ (xr+ex)*sin(place*PI*2.0/400.0+0.0001));
3524712015-05-26Martin Nilsson  int y=(int)(-text[i]->ysize()/2+yc +yt+
d697d71999-09-30Henrik Wallin  (yr+ex)*sin(-PI/2.0+place*PI*2.0/400.0+0.0001));
3524712015-05-26Martin Nilsson 
d697d71999-09-30Henrik Wallin  piediagram=piediagram->paste_alpha_color(text[i], @fg, x, y); }
e27f9e2005-11-15Martin Nilsson  diagram_data->ysize-=diagram_data->legend_size; diagram_data->image=piediagram;
d697d71999-09-30Henrik Wallin  return diagram_data; }