summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Wührer <def@gmx.at>2017-02-19 15:20:12 +0100
committerDavid Wührer <def@gmx.at>2017-02-19 15:20:12 +0100
commitfaf540b146dc7c4a48480673af9a8de56df2e34f (patch)
tree13d9b5750a3e956c2157f80aaa3cae4d9d441593
initial commit
-rw-r--r--piechart.c92
1 files changed, 92 insertions, 0 deletions
diff --git a/piechart.c b/piechart.c
new file mode 100644
index 0000000..aa52afd
--- /dev/null
+++ b/piechart.c
@@ -0,0 +1,92 @@
+/*
+ * BUGS:
+ * adjacient colours could have higher contrast
+ * negative angles
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+const float tau=(float)(M_PI*2);
+
+// draw sector
+void draw(float angle, char* label){
+ const float r=100;
+ static float progress=0;
+ static float overlap=0;
+ float fangle; if(angle<0)fangle=-angle;else fangle=angle-overlap;
+ // Mx,y : move to x,y
+ // Lx,y : draw line to x,y
+ // Arx,ry rot 0,0 x,y : arc with radii rx,ry rotated by rot large-arch or not,clockwise or not to point x,y
+ // z : closes the path
+ float x1=r*cosf(progress);
+ float y1=r*sinf(progress);
+ float x2=r*cosf(progress+fangle);
+ float y2=r*sinf(progress+fangle);
+ float divider=progress+fangle/2;
+ unsigned char rr=(unsigned char)(0xff*((divider)/(tau)));
+ unsigned char gg=(unsigned char)(0xff*((divider-tau/3)/(tau)));
+ unsigned char bb=(unsigned char)(0xff*((divider-2*tau/3)/(tau)));
+ printf("<path stroke=\"#000000\" fill=\"#%02x%02x%02x\" d=\"M250,250 L%f,%f A%f,%f 0 %d,%d %f,%f z\"/>",rr,gg,bb,250+x1,250+y1,r,r,(fangle>M_PI),1,250+x2,250+y2);
+ float xo=250+(3*r/2*cosf(divider));
+ float yo=250+(3*r/2*sinf(divider));
+ printf("<line stroke=\"#000000\" x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" />",250+(2*r/3*cosf(divider)),250+(2*r/3*sinf(divider)),xo,yo);
+ printf("<text x=\"%f\" y=\"%f\">%s</text>\n",xo,yo,label);
+ progress+=fangle;
+ overlap-=angle; // multiple overlaps accumulate
+ if(overlap<0)overlap=0;
+}
+// put preliminary data on the stack
+float scan_line (FILE* input, float sum){
+ char* line=NULL; size_t len=0;
+ if(getline(&line,&len,input) != -1){
+ { // chomp
+ char* l=&(line[strlen(line)-1]);
+ if(*l=='\n')*l='\0';
+ }
+ /* at the very least, we need a true value.
+ * everything following it can be label or whatever.
+ * if strtof does not find anything (or the value is miniscule), the line is obviously a comment and should be ignored.
+ * (if the value is too huge to handle, the output will be meaningless.)
+ *
+ * If the value is negative, it is meant to overlap with the previous record. Or records.
+ * The value would have to be ignored for computing the sum total.
+ */
+ char* label=line;
+ float number=strtof(label,&label);
+ if(number>0){
+ sum=scan_line(input,sum+number);
+ float angle=tau*number/sum;
+ draw(angle,label);
+ }else if(number<0){
+ sum=scan_line(input,sum);
+ float angle=tau*number/sum;
+ draw(angle,label);
+ }else{
+ sum=scan_line(input,sum);
+ printf("<!-- %s -->\n",label);
+ }
+ }
+ free(line);
+ return sum;
+}
+
+int main(int argc, char** argv){
+ FILE* input=stdin;
+ // getopts
+ // print boilerplate
+ puts("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n\
+<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1/EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n\
+<svg\n\
+ xmlns=\"http://www.w3.org/2000/svg\"\n\
+ version=\"1.1\"\n\
+ width=\"500\"\n\
+ height=\"500\"\n\
+ viewBox=\"0 0 500 500\"\n\
+>");
+ scan_line(input,0);
+ puts("</svg>");
+ return 0;
+}