/***********************************************************************/ /* Open Visualization Data Explorer */ /* (C) Copyright IBM Corp. 1989,1999 */ /* ALL RIGHTS RESERVED */ /* This code licensed under the */ /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */ /***********************************************************************/ /* * Piechart module to create a 2D piechart using * a list of percentages to define to angular * measure of a wedge. * Author: Donna Gresh * 05/20/97 * */ /*=====================Include Files===================================*/ #include #include #include #include #include /*=====================Definitions=====================================*/ typedef struct { float x, y; } Point2D; #define AUTORADIUSMIN .2 #define AUTORADIUSMAX 1.0 #define AUTOHEIGHTMIN .05 #define AUTOHEIGHTMAX .5 static int LabelsAreUnique(Array); static Array GetLabels(Object, Object); static RGBColor DEFAULT_EDGE_COLOR = {1.0, 1.0, 1.0}; static Error MakePie(Object, Object, int, float, Array, Group *, Group *, Array *, Array *, Field, int *, int); static Error MakePie3D(Object, Object, Field, float *, int); static Error ScalePie(Object, int, float *, int); static Error ScaleLabels(Object, int, float *); static RGBColor *CheckColors(Array, Field, int); static Error CheckLabels(int, Array, int *); static Error CheckHeight(Object, Object, Object, Object, Object, int, int *, float **); static Error CheckRadius(Object, Object, Object, Object, Object, int, int *, float **); static Error CopyComponents(Field, Field, Field, int, int, int); static Error AddData(float *, Field, Field, int, int); static Error AddColors(Group *, Group *, int, RGBColor *); static Error GetParameters(Object, Object, Object, Object, Object, float *, float *, float *, float *); #define FORMAT_LIST(type) \ { \ type * dataptr; \ int maxlen=0, i; \ char buf[2048]; \ dataptr = (type *)DXGetArrayData(component); \ for (i=0; imaxlen) maxlen=strlen(buf); \ } \ newarray = DXNewArray(TYPE_STRING, CATEGORY_REAL, 1, maxlen+1);\ for (i=0; i 1)) { DXSetError(ERROR_INVALID_DATA, "quality must be a scalar between 0 and 1"); goto error; } } else { quality = .25; } if (!In_percents) { DXSetError(ERROR_MISSING_DATA,"percents must be specified"); goto error; } /* get the percents flag */ if (In_percentflag) { if (!DXExtractNthString((Object)In_percentflag, 0, &flagstring)) { DXSetError(ERROR_INVALID_DATA, "percentflag must be one of `percents`, `fractions`, `values`"); goto error; } /* XXX note that upper case should be handled */ if (!strcmp(flagstring,"percents")) percentflag = 0; else if (!strcmp(flagstring,"fractions")) percentflag = 1; else if (!strcmp(flagstring,"values")) percentflag = 2; else { DXSetError(ERROR_INVALID_DATA, "percentflag must be one of `percents`, `fractions`, `values`"); goto error; } } else { percentflag = 2; } /* make the pie */ pie = DXNewGroup(); if (!pie) goto error; /* make the edges field */ edges = DXNewGroup(); if (!edges) goto error; labelfield = DXNewField(); if (!labelfield) goto error; if (In_showpercent) { if (!DXExtractInteger(In_showpercent, &show_percents)){ DXSetError(ERROR_INVALID_DATA,"showpercents must be 0 or 1"); goto error; } if ((show_percents < 0)||(show_percents > 1)) { DXSetError(ERROR_INVALID_DATA,"showpercents must be 0 or 1"); goto error; } } else { show_percents = 0; } if (In_labels) { labellist = GetLabels(In_labels, In_labelformat); if (!labellist) goto error; } /* this makes a simple 2D pie, of a single radius */ if (!MakePie(In_percents, In_colors, percentflag, quality, labellist, &pie, &edges, &labeloutput, &coloroutput, labelfield, &numwedges, show_percents)) goto error; /* * look at what the user passed in for the radius param, and * muck with the radius values */ if (!CheckRadius(In_radius, In_radiusscale, In_radiusmin, In_radiusmax, In_radiusratio, numwedges, &radtype, &radius)) goto error; /* * if the user passed in anything for the height param, muck with * the height values */ if (In_height) { if (!CheckHeight(In_height, In_heightscale, In_heightmin, In_heightmax, In_heightratio, numwedges, &dim, &height)) goto error; } /* * if the user didn't pass anything in for height, it's flat */ else dim = 0; /* non-flat*/ if ((dim == 1)||(dim == 2)) { if (!MakePie3D((Object)pie, (Object)edges, labelfield, height, dim)) goto error; if (!ScalePie((Object)pie, radtype, radius, 0)) goto error; if (!ScalePie((Object)edges, radtype, radius, 0)) goto error; if (!ScaleLabels((Object)labelfield, radtype, radius)) goto error; /* add normals for shading */ /* use call module to call FaceNormals, Normals */ DXModSetObjectInput(&input[0], NULL, (Object)pie); DXModSetObjectOutput(&output[0], NULL, (Object *)&newpie); if (DXCallModule("FaceNormals", 1, input, 1, output)==ERROR) goto error; DXModSetObjectInput(&input[0], NULL, (Object)edges); DXModSetObjectOutput(&output[0], NULL, (Object *)&newedges); if (DXCallModule("FaceNormals", 1, input, 1, output)==ERROR) goto error; out[0] = (Object)newpie; out[1] = (Object)newedges; } /* flat */ else { if (!ScalePie((Object)pie, radtype, radius, 0)) goto error; if (!ScalePie((Object)edges, radtype, radius, 0)) goto error; if (!ScaleLabels((Object)labelfield, radtype, radius)) goto error; /* since the edges are lines, add some fuzz */ if (!DXSetFloatAttribute((Object)edges, "fuzz", 4)) goto error; out[0] = (Object)pie; out[1] = (Object)edges; } out[2] = (Object)labelfield; out[3] = (Object)labeloutput; out[4] = (Object)coloroutput; DXFree((Pointer)height); DXFree((Pointer)radius); DXDelete((Object)labellist); return OK; error: DXDelete((Object) pie); DXDelete((Object) edges); DXDelete((Object) labelfield); DXDelete((Object) coloroutput); DXFree((Pointer)height); DXFree((Pointer)radius); DXDelete((Object)labellist); out[0]=NULL; out[1]=NULL; out[2]=NULL; out[3]=NULL; out[4]=NULL; return ERROR; } static Error MakePie(Object In_percents, Object In_colors, int percentflag, float quality, Array labellist, Group *pie, Group *edges, Array *labeloutput, Array *coloroutput, Field labelfield, int *numwedges, int showpercents) { Array data, c; Array colors=NULL; Array labelpositions=NULL; float labelangle; RGBColor *col; RGBColor *cptr=NULL; char *labeloutput_ptr=NULL; Type type; Category category; Object member, newpie, newedges; int numitems, rank, shape[32]; float *dataptr, angle, arc, cumpercent; Field F1=NULL, F2=NULL, F3=NULL; int i, poscount, concount, maxstringlength; Array wedgespositions=NULL, wedgesconnections=NULL, wedgesdata=NULL; Array edgesconnections=NULL, edgesdata=NULL; Array wedgescolors=NULL, edgescolors=NULL; Triangle tri; float *percentarray=NULL, cumvalue; Point2D pt2D, labelpos; char *stringlabel=NULL, *nthstring, *tmpstring; ModuleInput input[20]; ModuleOutput output[20]; Object colormap; float drg2rad = 4*atan(1.)/180.; /* In_percents can be a field or an array */ switch (DXGetObjectClass(In_percents)) { case CLASS_FIELD: data = (Array)DXGetComponentValue((Field)In_percents,"data"); if (!data) { DXSetError(ERROR_MISSING_DATA,"missing data component"); goto error; } /* does the input have colors? */ colors = (Array)DXGetComponentValue((Field)In_percents,"colors"); break; case CLASS_ARRAY: data = (Array)In_percents; break; default: DXSetError(ERROR_INVALID_DATA,"invalid percents"); goto error; } if (!DXGetArrayInfo(data,&numitems, &type, &category, &rank, shape)) goto error; *numwedges = numitems; /* Input colors param has precendence over colors in the field */ if (In_colors) { /* check that In_colors is an array */ if (DXGetObjectClass(In_colors) != CLASS_ARRAY) { DXSetError(ERROR_INVALID_DATA,"invalid colors parameter"); goto error; } cptr = CheckColors((Array)In_colors, NULL, numitems); if (!cptr) goto error; } else if (colors) { cptr = CheckColors(colors, (Field)In_percents, numitems); if (!cptr) goto error; } /* check the labels */ if (labellist) { if (!CheckLabels(numitems, labellist, &maxstringlength)) goto error; } else maxstringlength=0; stringlabel = DXAllocate((maxstringlength+10)*sizeof(char)); if (!stringlabel) goto error; /* make the percents and colors arrays. These are the extra outputs */ *labeloutput = DXNewArray(TYPE_STRING, CATEGORY_REAL, 1, maxstringlength+10); if (!*labeloutput) goto error; *coloroutput = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, 3); if (!*coloroutput) goto error; if (!DXAddArrayData(*labeloutput, 0, numitems, NULL)) goto error; if (!DXAddArrayData(*coloroutput, 0, numitems, NULL)) goto error; if (category != CATEGORY_REAL) { DXSetError(ERROR_INVALID_DATA,"percents must be real"); goto error; } if (!((rank == 0)||((rank == 1)&&(shape[0]==1)))) { DXSetError(ERROR_INVALID_DATA,"percents must be scalar"); goto error; } percentarray = DXAllocate(numitems*sizeof(float)); switch (type) { case (TYPE_FLOAT): FILL_PERCENT_ARRAY(float); break; case (TYPE_INT): FILL_PERCENT_ARRAY(int); break; case (TYPE_BYTE): FILL_PERCENT_ARRAY(byte); break; case (TYPE_SHORT): FILL_PERCENT_ARRAY(short); break; case (TYPE_UINT): FILL_PERCENT_ARRAY(uint); break; case (TYPE_UBYTE): FILL_PERCENT_ARRAY(ubyte); break; case (TYPE_USHORT): FILL_PERCENT_ARRAY(ushort); break; case (TYPE_DOUBLE): FILL_PERCENT_ARRAY(double); break; default: DXSetError(ERROR_INVALID_DATA,"unknown data type"); goto error; } labelpositions = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, 2); angle = 0; cumpercent = 0; for (i=0; i radiusscale, * radiusminval -> radiusscale*ratio */ if (numitems == 1) { **radius = maxval; *radtype = 0; } else { if ((maxval - minval) == 0) { DXSetError(ERROR_INVALID_DATA,"radiusmax and radiusmin are equal"); goto error; } for (i=0; i