home *** CD-ROM | disk | FTP | other *** search
/ pc.louisiana.edu/pub/unix/ / Louisiana_UNIX.tar / Louisiana_UNIX / xspread3.0.zoo / plot_pie.c < prev    next >
C/C++ Source or Header  |  1994-06-02  |  15KB  |  432 lines

  1. /*
  2.  * Copyright (C) 1992  Board of Regents of the University of Wisconsin
  3.  * on behalf of the Department of Electrical Engineering and Computer
  4.  * Science, University of Wisconsin-Milwaukee, Milwaukee, WI 53201.
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2 of the License, or
  9.  * (at your option) any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * a copy of which is included here in file "GNU_GENERAL"
  18.  * along with this program; if not, write to the Free Software
  19.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  *
  21.  * The programs in this directory were developed by software engineering 
  22.  * teams as part of the course "Introduction to Software Engineering" 
  23.  * under the supervision of Professor G. Davida.
  24.  * This is a modification of a program written or modified by
  25.  * others.  The original copyrights, as per GNU General Public License,
  26.  * may still be applicable.  The UWM copyright is applicable only
  27.  * the those parts generated at UWM.
  28.  *
  29.  * Please send all changes, enhancements, and other comments about this
  30.  * software to
  31.  *             soft-eng@cs.uwm.edu
  32.  *
  33.  * No Warranty, expressed or implied, comes with this software.
  34.  * This software is intended to be used by not-for-profit
  35.  * organizations or by individuals for personal HOME use. 
  36.  * This software, or any of its parts, may not be used by for-profit
  37.  * organization, regardless of application or intended product or
  38.  * customer, without the permission of the Board of Regents of the 
  39.  * University  of Wisconsin is strictly forbidden. 
  40.  *
  41.  * Contact:    soft-eng@cs.uwm.edu
  42.  *            or
  43.  *        
  44.  *        Software Engineering Coordinator
  45.  *        Computer Science
  46.  *            Department of EECS
  47.  *        University of Wisconsin - Milwaukee
  48.  *        Milwaukee, WI  53201
  49.  *        414-229-4677
  50.  *
  51.  *        HISTORY,CLAIMS and CONTRIBUTIONS
  52.  */
  53. /***************************************************************************
  54.  * This procedure produces a Pie Graph for the selected values in the current
  55.  * spreadsheet.  It calculates the percentage of each cell, and then draws a
  56.  * Pie slice the size according to the percentage.  It uses patterns located
  57.  * in the file pattern.h which were created using the bitmap editor. 
  58.  * Dan Gruber - November 1991         
  59.  *
  60.  * Modified 5/94 by Dan Coppersmith to improve user
  61.  * friendliness of error functions. 
  62.  **************************************************************************/ 
  63.  
  64. #include <math.h>
  65. #include <stdio.h>
  66. #include <X11/Xlib.h>
  67. #include <X11/Xutil.h>
  68. #include "config.h"
  69. #include "plot.h" 
  70. #include "graphic_gvar.h"
  71. #include "sc.h"
  72. #include "scXstuff.h"
  73. #include "pattern.h"
  74. #define TITLE "XSPREAD-Grapher (Pie Plot)"
  75. #define PIE_D 300   /* Pie Diameter */
  76. #define PIE_R 150   /* Pie Radius   */
  77. #define PI       3.14159265358979323846
  78.  
  79. #ifndef irint
  80. #define irint(x) floor((x)+0.5)
  81. #endif
  82.  
  83. /*
  84.  * This structure forms the WM_HINTS property of the window,
  85.  * letting the window manager know how to handle this window.
  86.  * See Section 9.1 of the Xlib manual.
  87.  */
  88.  
  89.    XWMHints     MyWMHints = {
  90.       (InputHint|StateHint),   /* flags         */
  91.           False,                   /* input         */
  92.           NormalState,             /* initial_state */
  93.       0,                       /* icon pixmap   */
  94.       0,                       /* icon window   */
  95.           0, 0,                    /* icon location */
  96.           0,                       /* icon mask     */
  97.           0,                       /* Window group  */
  98.    };
  99.  
  100.  
  101. plot_pie()
  102. {   
  103.     int i, j, k, len;
  104.     int text_w;
  105.     int X, Y, X1, Y1, Temp_X,Temp_Y;
  106.     struct ent *p, *val, *next_val;
  107.     int  looping = 1;             /* true if we shouldn't exit yet           */
  108.     int draw  = 0;                /* true if we should paint the window      */
  109.     int cells = 0; 
  110.     int slice;                    /* Slice number                            */
  111.     double Range_Total = 0;       /* Total of all of the cell values         */
  112.     double Percentage = 0;        /* Percentage of the slice                 */ 
  113.     double Angle_Size = 0;        /* Angle size of the slice                 */
  114.     double Starting_Angle = 0;    /* Starting position for each slice        */
  115.     double Rad_Angle = 0;         /* The angle in radians                    */ 
  116.     double Bisector_Angle = 0;    /* The 'middle' of the angle               */
  117.     double Label_R = 0;           /* Radius of the circle for drawing labels */
  118.     Pixmap Pattern;               /* Pattern for a given slice               */
  119.           
  120.     char str[100];
  121.     char per_str[10];
  122.     register int c;
  123.  
  124.     int argc = 0;
  125.     char **argv;
  126.  
  127.  
  128.  
  129. /* check that we have enough valid x values.  While we are looping,
  130.  * determine the minimum and maximum x values, in case we need them
  131.  */
  132.  
  133.    Range_Total = 0;
  134.    for (i=graphic_range[0].r1; i <= graphic_range[0].r2; i++) { 
  135.      p = lookat( i, graphic_range[0].c);
  136.      val = lookat( i, graphic_range[1].c);
  137.      if ((p->label) && (val->v)) /*FIXME continue;*/
  138.        {
  139.            Range_Total = Range_Total + val->v;
  140.            cells++;
  141.        } 
  142.    } /* for i */
  143.  
  144.    if (cells < 1) {
  145.      fprintf(stderr,"\007");
  146.      if (graphic_range[0].r2 - graphic_range[0].r1 > 1)
  147.     message("x values must be strings");
  148.      else
  149.     message("Not enough valid Labels (X values)");
  150.      return;
  151.    }
  152.  
  153.    /* 
  154.     * Open a new display window
  155.     */
  156.  
  157.    /*
  158.     * Select colors for the border,  the window background,  and the
  159.     * foreground.
  160.     */
  161.  
  162.    bd = WhitePixel(dpy, DefaultScreen(dpy));
  163.    bg = BlackPixel(dpy, DefaultScreen(dpy));
  164.    fg = WhitePixel(dpy, DefaultScreen(dpy));
  165.  
  166.    /*
  167.     * Set the border width of the window,  and the gap between the text
  168.     * and the edge of the window, "pad".
  169.     */
  170.  
  171.    pad = BORDER;
  172.    bw = 1;
  173.  
  174.    /*
  175.     * Deal with providing the window with an initial position & size.
  176.     * Fill out the XSizeHints struct to inform the window manager.
  177.     */
  178.  
  179.    xsh.width = XTextWidth(curfont, TITLE, 80 + pad * 2);
  180.    xsh.flags = (PPosition | PSize);
  181.    xsh.height = WIN_H; 
  182.    xsh.width = WIN_W; 
  183.    xsh.x = (DisplayWidth(dpy, DefaultScreen(dpy)) - xsh.width) / 2;
  184.    xsh.y = (DisplayHeight(dpy, DefaultScreen(dpy)) - xsh.height) / 2;
  185.  
  186.    /*
  187.     * Create the Window with the information in the XSizeHints, the
  188.     * border width,  and the border & background pixels.
  189.     */
  190.  
  191.    win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy),
  192.                  xsh.x, xsh.y, xsh.width, xsh.height,
  193.                  bw, bd, bg);
  194.  
  195.    /*
  196.     * Set the standard properties for the window managers. 
  197.     */
  198.  
  199.    XSetStandardProperties(dpy, win, TITLE, TITLE, 
  200.          None, argv, argc, &xsh);
  201.    XSetWMHints(dpy, win, &MyWMHints);
  202.  
  203.    /*
  204.     * Ensure that the window's colormap field points to the default
  205.     * colormap,  so that the window manager knows the correct colormap to
  206.     * use for the window.   Also,  set the window's Bit Gravity to reduce 
  207.     * Expose events.
  208.     */
  209.  
  210.    xswa.colormap = DefaultColormap(dpy, DefaultScreen(dpy));
  211.    xswa.bit_gravity = CenterGravity;
  212.    XChangeWindowAttributes(dpy, win, (CWColormap | CWBitGravity), &xswa);
  213.  
  214.  
  215.    /* 
  216.     * Map the window to make it visible.  
  217.     */
  218.   
  219.    XMapWindow(dpy, win);
  220.  
  221.    /*
  222.     * Find out the dimension of the window.
  223.     */
  224.  
  225.    if (XGetWindowAttributes(dpy, win, &xwa) == 0){
  226.       fprintf(stderr,"plot_pie: Can't access attributes for graph window\n");
  227.       exit(1);    
  228.    }
  229.  
  230.    XClearWindow(dpy, win);
  231.    XSelectInput(dpy,win, ButtonPressMask|KeyPressMask|ExposureMask);
  232.  
  233.  
  234. while(looping)
  235.  {   
  236.  
  237.     XEvent event;
  238.  
  239.     XNextEvent(dpy,&event);
  240.     switch (event.type){
  241.       case KeyPress: 
  242.       case ButtonPress: looping = 0; 
  243.             break;
  244.       case Expose: draw = 1;
  245.     }
  246.  
  247.  
  248.     /* 
  249.      * if not drawing, go back and get another event 
  250.      */
  251.  
  252.     if (!draw) continue;
  253.  
  254.     /*
  255.      * Draw titles
  256.      */
  257.  
  258.     /* first graph title */
  259.     len = strlen(graphic_title[0]);   
  260.     text_w= XTextWidth(curfont, graphic_title[0], len);
  261.     XDrawImageString(dpy, win, maingcreversed, (WIN_W-text_w)/2, RECT_Y/3,
  262.                      graphic_title[0], len);
  263.  
  264.     /* second graph title */
  265.     len = strlen(graphic_title[1]);
  266.     text_w= XTextWidth(curfont, graphic_title[1], len);
  267.     XDrawImageString(dpy, win, maingcreversed, 
  268.              (WIN_W - text_w)/2  , RECT_Y * 2/3,
  269.                      graphic_title[1], len);
  270.  
  271.     Starting_Angle = 0;
  272.     slice = 1;
  273.     for (i=graphic_range[0].r1,j=graphic_range[1].r1; 
  274.         (i<=graphic_range[0].r2) && (j<=graphic_range[1].r2); i++, j++)
  275.     {  
  276.        
  277.       if (!((p=lookat(i,graphic_range[0].c))->label))
  278.         continue;
  279.  
  280.       val=lookat(i,graphic_range[1].c);
  281.  
  282.       /* Calculate the percentage of the slice */
  283.       Percentage = (val->v / Range_Total);
  284.      
  285.       /* 
  286.        * If this is the last slice to be drawn, take '360 - Starting_Angle'
  287.        * in case there is round-off errors.   
  288.        */
  289.  
  290.       if (i == graphic_range[0].r2)
  291.          Angle_Size = 360 - Starting_Angle;
  292.       else 
  293.          Angle_Size = Percentage * 360;
  294.  
  295.       /* Choose a pattern for drawing (They are located in pattern.h) */
  296.       switch (slice) {
  297.         case 1 : Pattern = XCreateBitmapFromData(dpy,win,white_bits,
  298.                      white_width, white_height);
  299.                      break;
  300.         case 2 : Pattern = XCreateBitmapFromData(dpy,win,gray3_bits,
  301.                      gray3_width, gray3_height);
  302.                      break;
  303.         case 3 : Pattern = XCreateBitmapFromData(dpy,win,gray5_bits,
  304.                      gray5_width, gray5_height);
  305.                      break;
  306.         case 4 : Pattern = XCreateBitmapFromData(dpy,win,gray2_bits,
  307.                      gray2_width, gray2_height);
  308.                      break;
  309.         case 5 : Pattern = XCreateBitmapFromData(dpy,win,gray4_bits,
  310.                      gray4_width, gray4_height);
  311.                      break;
  312.         case 6 : Pattern = XCreateBitmapFromData(dpy,win,gray1_bits,
  313.                      gray1_width, gray1_height);
  314.                      break;
  315.         case 7 : Pattern = XCreateBitmapFromData(dpy,win,black_bits,
  316.                      black_width, black_height);
  317.                      break;
  318.         case 8 : Pattern = XCreateBitmapFromData(dpy,win,diag_r_bits,
  319.                      diag_r_width, diag_r_height);
  320.                      break;
  321.         case 9 : Pattern = XCreateBitmapFromData(dpy,win,dark_wide_weave_bits,
  322.                      dark_wide_weave_width, dark_wide_weave_height);
  323.                      break;
  324.         case 10: Pattern = XCreateBitmapFromData(dpy,win,light_diamond_bits,
  325.                      light_diamond_width, light_diamond_height);
  326.                      break;
  327.         case 11: Pattern = XCreateBitmapFromData(dpy,win,diag_l_bits,
  328.                      diag_l_width, diag_l_height);
  329.                      break;
  330.         case 12: Pattern = XCreateBitmapFromData(dpy,win,light_root_weave_bits,
  331.                      light_root_weave_width, light_root_weave_height);
  332.                      break;
  333.         case 13: Pattern = XCreateBitmapFromData(dpy,win,vert_lines_bits,
  334.                      vert_lines_width, vert_lines_height);
  335.                      break;
  336.         case 14: Pattern = XCreateBitmapFromData(dpy,win,dark_root_weave_bits,
  337.                      dark_root_weave_width, dark_root_weave_height);
  338.                      break;
  339.         case 15: Pattern = XCreateBitmapFromData(dpy,win,checker_bits,
  340.                      checker_width, checker_height);
  341.                      break;
  342.         case 16: Pattern = XCreateBitmapFromData(dpy,win,dark_cross_weave_bits,
  343.                      dark_cross_weave_width, dark_cross_weave_height);
  344.                      break;
  345.         case 17: Pattern = XCreateBitmapFromData(dpy,win,dark_diamond_bits,
  346.                      dark_diamond_width, dark_diamond_height);
  347.                      break;
  348.         case 18: Pattern = XCreateBitmapFromData(dpy,win,light_cross_weave_bits,
  349.                      light_cross_weave_width, light_cross_weave_height);
  350.                      break;
  351.         case 19: Pattern = XCreateBitmapFromData(dpy,win,horiz_lines_bits,
  352.                      horiz_lines_width, horiz_lines_height);
  353.                      break;
  354.         case 20: Pattern = XCreateBitmapFromData(dpy,win,light_wide_weave_bits,
  355.                      light_wide_weave_width, light_wide_weave_height);
  356.                      break;
  357.         
  358.       };
  359.       
  360.       /* Set the fill style to allow for drawing patterns */ 
  361.       XSetStipple(dpy,maingcreversed,Pattern);
  362.       XSetFillStyle(dpy, maingcreversed, FillStippled);
  363.       
  364.       /* Draw a single pie slice */
  365.       XFillArc(dpy, win, maingcreversed,
  366.             (WIN_W/2)-(PIE_R), (WIN_H/2)-(PIE_R)*4/5, PIE_D, PIE_D,
  367.             irint(Starting_Angle)*64, irint(Angle_Size*64) );
  368.  
  369.       /* Set fill style back to solid for drawing lines */
  370.       XSetFillStyle(dpy, maingcreversed, FillSolid); 
  371.        
  372.       /* 
  373.        * This section converts the Starting_Angle from degrees to radians 
  374.        * and then calculates the proper positions for drawing the line
  375.        * separators, and then draws them.
  376.        */ 
  377.  
  378.       Rad_Angle = Starting_Angle * PI / 180;
  379.       Temp_X = (PIE_R) * cos(Rad_Angle);
  380.       Temp_Y = -((PIE_R) * sin(Rad_Angle));
  381.       X = Temp_X + (WIN_W/2);
  382.       Y = Temp_Y + (WIN_H/2) + (PIE_R/5);
  383.       XDrawLine(dpy,win,maingcreversed,WIN_W/2,(WIN_H/2 + PIE_R/5),X,Y); 
  384.  
  385.       /* 
  386.        * This section draws the label for the given slice by calculating the
  387.        * angle bisector of the slice and then draws the Labels outside the
  388.        * Pie a distance of one fifth the radius of the Pie.
  389.        */
  390.  
  391.       Label_R = PIE_R + (PIE_R/5);
  392.       Bisector_Angle = Starting_Angle + (Angle_Size/2);
  393.       Rad_Angle = Bisector_Angle * PI / 180;
  394.       Temp_X = (Label_R) * cos(Rad_Angle);
  395.       Temp_Y = -((Label_R) * sin(Rad_Angle));
  396.       X1 = Temp_X + (WIN_W/2);
  397.       Y1 = Temp_Y + (WIN_H/2) + (PIE_R/5);
  398.       strncpy(str,p->label,strlen(p->label));
  399.       len = strlen(p->label); 
  400.       str[len] = '\0';
  401.       sprintf(per_str,"%.1f",(Percentage * 100));
  402.       strcat(str, " (");
  403.       strcat(str,per_str);
  404.       strcat(str,"%)");
  405.       len = strlen(str);
  406.       text_w = XTextWidth(curfont, str, len);
  407.       
  408.       /* If the slice is on the left side of the Pie, make proper adjustment */
  409.       if ((Bisector_Angle > 90) && (Bisector_Angle <= 270))
  410.           X = X1 - text_w;
  411.       else
  412.           X = X1;
  413.       Y = Y1 + curfontheight/2;
  414.       XDrawImageString(dpy,win,maingcreversed,X,Y,str,len);
  415.   
  416.       /* Calculate the next Starting_Angle */
  417.       /*Starting_Angle = irint(Starting_Angle) + irint(Angle_Size);*/
  418.       /* irint changed to rint by Bob Parbs */
  419.       Starting_Angle = (Starting_Angle) + (Angle_Size);
  420.       slice++;
  421.     } 
  422.  
  423.     /* Draw a complete circle around the Pie */
  424.     XSetFillStyle(dpy, maingcreversed, FillSolid); 
  425.     XDrawArc(dpy, win, maingcreversed,(WIN_W/2)-(PIE_R),(WIN_H/2)-(PIE_R)*4/5, 
  426.              PIE_D, PIE_D, 0, 360*64); 
  427.   } /* end of while */  
  428.  
  429.   XUnmapWindow(dpy, win);
  430.   XDestroyWindow(dpy, win);
  431. }
  432.