home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Graphics / Plotting / QuickPlot / Source / Plot.m < prev    next >
Encoding:
Text File  |  1995-06-12  |  7.0 KB  |  380 lines

  1.  
  2. /*    Program By Fred Richards, Copyright 1990.    */
  3. /*                            */
  4. /*    This software is provided free of charge    */
  5. /*    and without warranty.  The source code may    */
  6. /*    be distributed freely provided this copyright    */
  7. /*    notice remains in tact.                */
  8.  
  9.  
  10. #import "Plot.h"
  11. #import "PlotView.h"
  12. #import    <stdlib.h>
  13. #import <string.h>
  14.  
  15.  
  16. @implementation Plot
  17.  
  18. // These 'set***' methods attach this to the objects in the Window
  19.  
  20. - setCanvas:anObject
  21. {
  22.     canvas = anObject;
  23.     return self;
  24. }
  25.  
  26. - setXMin:anObject
  27. {
  28.     xMin = anObject;
  29.     return self;
  30. }
  31.  
  32. - setYMax:anObject
  33. {
  34.     yMax = anObject;
  35.     return self;
  36. }
  37.  
  38. - setYMin:anObject
  39. {
  40.     yMin = anObject;
  41.     return self;
  42. }
  43.  
  44. - setXMax:anObject
  45. {
  46.     xMax = anObject;
  47.     return self;
  48. }
  49.  
  50. - setPlotBox:anObject
  51. {
  52.     plotBox = anObject;
  53.     return self;
  54. }
  55.  
  56.  
  57. // These methods return the values of the instance variables
  58.  
  59. - (BOOL )border:sender {    return border;    }
  60.  
  61. - (BOOL )axes:sender {    return axes;    }
  62.  
  63. - (BOOL )lines:sender {    return lines;    }
  64.  
  65. - (int )style:sender {    return style;    }
  66.  
  67. - (NXPoint *)data {    return data;    }
  68.  
  69. - (int )dSize {        return dCount;    }
  70.  
  71. - (NXCoord )xmin:sender {    return min.x; }
  72.  
  73. - (NXCoord )xmax:sender {    return max.x; }
  74.  
  75. - (NXCoord )ymin:sender {    return min.y; }
  76.  
  77. - (NXCoord )ymax:sender {    return max.y; }
  78.  
  79. - (char *)fileName:sender; {    return fileName; }
  80.  
  81. // These set*** methods set the instance variables from the control-
  82. // panel objects.
  83.  
  84. - setLines:sender
  85. {
  86.     lines = [sender state];
  87.     return self;
  88. }
  89.  
  90. - setAxes:sender
  91. {
  92.     axes = [sender state];
  93.     return self;
  94. }
  95.  
  96. - setBorder:sender
  97. {
  98.     border = [sender state];
  99.     return self;
  100. }
  101.  
  102. - setStyle:sender
  103. {
  104.     style = [sender selectedRow];
  105.     return self;
  106. }
  107.  
  108. - setMinmax:sender
  109. {
  110.     minmax = [sender selectedCol];
  111.     if (minmax)  {
  112.       [self getXmin:self];    [self getXmax:self];
  113.       [self getYmin:self];    [self getYmax:self];
  114.     } else  {
  115.       min.x = dMin.x;    max.x = dMax.x;
  116.       min.y = dMin.y;    max.y = dMax.y;
  117.       [self resetXmin:self];    [self resetXmax:self];
  118.       [self resetYmin:self];    [self resetYmax:self];
  119.     }
  120.     return self;
  121. }
  122.  
  123.  
  124. // read the min or max value from the control panel
  125.  
  126. - getXmin:sender
  127. {
  128.     min.x = [xMin floatValueAt:0];
  129.     return self;
  130. }
  131.  
  132. - getXmax:sender
  133. {
  134.     max.x = [xMax floatValueAt:0];
  135.     return self;
  136. }
  137.  
  138. - getYmin:sender
  139. {
  140.     min.y = [yMin floatValueAt:0];
  141.     return self;
  142. }
  143.  
  144. - getYmax:sender
  145. {
  146.     max.y = [yMax floatValueAt:0];
  147.     return self;
  148. }
  149.  
  150.  
  151. // reset the data limits shown in the control panel
  152.  
  153. - resetXmin:sender
  154. {
  155.     [xMin setFloatValue:(float )min.x at:0];
  156.     return self;
  157. }
  158.  
  159. - resetXmax:sender
  160. {
  161.     [xMax setFloatValue:(float )max.x at:0];
  162.     return self;
  163. }
  164.  
  165. - resetYmin:sender
  166. {
  167.     [yMin setFloatValue:(float )min.y at:0];
  168.     return self;
  169. }
  170.  
  171. - resetYmax:sender
  172. {
  173.     [yMax setFloatValue:(float )max.y at:0];
  174.     return self;
  175. }
  176.  
  177. // Change the Plot title in the window to reflect
  178. // the data-file name
  179.  
  180. - setBoxTitle:(char *)aTitle
  181. {
  182.     [plotBox setTitle:(const char *)aTitle];
  183.     return self;
  184. }
  185.  
  186.  
  187. // Get a fileName:  this will be the PostScript file where the
  188. // PlotView will write its code if a 'Save' is requested from the main menu
  189.  
  190. - setFileName:(char *)aPSfile
  191. {
  192.     if (fileName)
  193.       free(fileName);
  194.     fileName = calloc(strlen(aPSfile)+1, sizeof(char));
  195.     strcpy(fileName, aPSfile);
  196.     return self;
  197. }
  198.  
  199.  
  200. // This method sets things up so that PlotView:drawSelf
  201. // can do all the drawing work.
  202.  
  203. - drawPlot:sender
  204. {
  205.     if (!data)
  206.       return self;
  207.  
  208.     if ([self setupBorder:self])
  209.       [plotBox display];
  210.     return self;
  211. }
  212.  
  213. // Allocate enough memory and read the data points
  214.  
  215. - (int )readDataFrom:(FILE *)aDataStream
  216. {
  217.     double    x, y;
  218.     int        i;
  219.  
  220.     /* First read through the file to see how big it is */
  221.     
  222.     i = 0;
  223.     while (fscanf(aDataStream, "%lf %lf\n", &x, &y) == 2)
  224.       i++;
  225.  
  226.     /* If it was empty, then don't discard the old data */
  227.  
  228.     if (i == 0)
  229.       return 0;
  230.  
  231.     /* Now read the data into memory */
  232.     
  233.     dCount = i;
  234.  
  235.     if (data)
  236.       free(data);
  237.     data = (NXPoint *)calloc(dCount, sizeof(NXPoint));
  238.     rewind(aDataStream);
  239.     for (i = 0; i < dCount; i++)  {
  240.       fscanf(aDataStream, "%lf %lf\n", &x, &y);
  241.       data[i].x = (float )x;
  242.       data[i].y = (float )y;
  243.     }
  244.     return dCount;
  245. }
  246.  
  247.  
  248. // Go through the data set and find values for dMin.x, dMax.x, dMin.y, dMax.y
  249.  
  250. - findMinAndMax
  251. {
  252.     if (data)  {
  253.       int    i;
  254.       dMin.x = dMax.x = data[0].x;
  255.       dMin.y = dMax.y = data[0].y;
  256.       for (i = 1; i < dCount; i++)  {
  257.     if (data[i].x < dMin.x)
  258.       dMin.x = data[i].x;
  259.     else if (data[i].x > dMax.x)
  260.       dMax.x = data[i].x;
  261.     if (data[i].y < dMin.y)
  262.       dMin.y = data[i].y;
  263.     else if (data[i].y > dMax.y)
  264.       dMax.y = data[i].y;
  265.       }
  266.     }
  267.     return self;
  268. }
  269.     
  270.  
  271. // This message sends the appropriate min and max to the PlotView
  272.  
  273. - (BOOL )setupBorder:sender
  274. {
  275.     NXSize    newSize;
  276.  
  277.     /* Start by setting up the right scale */
  278.  
  279.     if (minmax)  {
  280.       [self getXmin:self];    [self getXmax:self];
  281.       [self getYmin:self];    [self getYmax:self];
  282.     } else  {
  283.       min.x = dMin.x;    max.x = dMax.x;
  284.       min.y = dMin.y;    max.y = dMax.y;
  285.       [self resetXmin:self];    [self resetXmax:self];
  286.       [self resetYmin:self];    [self resetYmax:self];
  287.     }
  288.  
  289.     newSize.width = max.x - min.x;
  290.     newSize.height = max.y - min.y;
  291.     if (newSize.width == 0 || newSize.height == 0)  {
  292.       NXRunAlertPanel("Plot", "The graph width and height must be > 0",
  293.               "OK", NULL, NULL, NULL);
  294.       return NO;
  295.     }
  296.     [canvas setDrawSize:(newSize.width + 0.2*newSize.width)
  297.     :(newSize.height + 0.2*newSize.height)];
  298.  
  299.     [canvas setDrawOrigin:(min.x - 0.1*newSize.width)
  300.     :(min.y - 0.1*newSize.height)];
  301.  
  302.     return YES;
  303. }
  304.  
  305. // Use the OpenPanel object to get a fileName
  306.  
  307. - open:sender
  308. {
  309.     char const    *fileTypes[2] = {0,0};    // this type is all ASCII files
  310.     char    fname[1024];
  311.  
  312.     id openPanel = [OpenPanel new];
  313.     if ([openPanel runModalForTypes:fileTypes])  {
  314.       strncpy(fname, [openPanel filename], 1024);
  315.       [self openFile:fname];
  316.     }
  317.     return self;
  318. }
  319.  
  320. - openFile:(char *)aDataFile
  321. {
  322.     FILE    *dataStream;
  323.     char    psFile[1024];
  324.  
  325.     if ((dataStream = fopen(aDataFile, "r")) == NULL)  {
  326.       NXRunAlertPanel("Open", "Cannot open %s", "OK", NULL, NULL, aDataFile);
  327.       return self;
  328.     }
  329.  
  330.     if ([self readDataFrom:dataStream] == 0)  {
  331.       NXRunAlertPanel("Read", "Couldn't read any data from %s", "OK",
  332.               NULL, NULL, aDataFile);
  333.       fclose(dataStream);
  334.       return self;
  335.     }
  336.     fclose(dataStream);
  337.  
  338.     [self findMinAndMax];
  339.     [self setBoxTitle:aDataFile];
  340.     [self drawPlot:self] ;
  341.     
  342.     return self;
  343. }
  344.  
  345.  
  346. // Tell the PlotView to write its PostScript code to fileName
  347.  
  348. - save:sender
  349. {
  350.     if (fileName)
  351.       [canvas savePSCode:fileName];
  352.     else
  353.       [self saveAs:sender];
  354.  
  355.     return self;
  356. }
  357.  
  358. // Get a fileName and then tell the PlotView to save
  359. // its PostScript code there
  360.  
  361. - saveAs:sender
  362. {
  363.     id savePanel = [SavePanel new];
  364.  
  365.     if (fileName)
  366.       free(fileName);
  367.  
  368.     [savePanel setRequiredFileType:"ps"];
  369.     if ([savePanel runModal])  {
  370.       fileName = calloc(strlen([savePanel filename])+1, sizeof(char));
  371.       strcpy(fileName, [savePanel filename]);
  372.       [self save:sender];
  373.     }
  374.  
  375.     return self;
  376. }
  377.  
  378.  
  379. @end
  380.