home *** CD-ROM | disk | FTP | other *** search
/ Education Sampler 1992 [NeXTSTEP] / Education_1992_Sampler.iso / Programming / Source / HippoDraw / hippo / hippodisplay.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-28  |  42.4 KB  |  1,893 lines

  1. /*
  2.  * hippodisplay.c - display parameter routines for hippo.
  3.  *
  4.  * Copyright (C)  1991  The Board of Trustees of The Leland Stanford
  5.  * Junior University.  All Rights Reserved.
  6.  *
  7.  * $Id: hippodisplay.c,v 3.22 1992/04/24 01:13:29 rensing Rel $
  8.  *
  9.  * by jonas karlsson, at SLAC, August 1990
  10.  *  split up by Paul Rensing, Feb 28,1991
  11.  */
  12.  
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <math.h>
  16. #include <string.h>
  17. #include <ctype.h>
  18. #include <float.h>
  19.  
  20. #include "hippo.h"
  21. #ifdef VM
  22. #include "h_util.h"
  23. #else
  24. #include "hippoutil.h"
  25. #endif
  26.  
  27. GLOB_QUAL const char hippodisplay_c_rcsid[] = 
  28.      "$Id: hippodisplay.c,v 3.22 1992/04/24 01:13:29 rensing Rel $";
  29.  
  30. #define WINDWIDTH 500.0
  31. #define WINDHEIGHT 500.0
  32. #define TOPMARGIN 40.0        /* 1 inch margins */
  33. #define BOTTOMMARGIN 80.0
  34. #define LEFTMARGIN 80.0
  35. #define RIGHTMARGIN 40.0
  36. #ifdef THINK_C
  37. /* can't do arithmetic with constants *8-( */
  38. #define WWMINUSLR 380.0
  39. #define WHMINUSTB 380.0
  40. #else
  41. #define WWMINUSLR (WINDWIDTH-LEFTMARGIN-RIGHTMARGIN)
  42. #define WHMINUSTB (WINDHEIGHT-TOPMARGIN-BOTTOMMARGIN)
  43. #endif
  44.  
  45. /*
  46.  * bug fix for IBM & THINKC: FLT_MAX calls a function, so it can't be used
  47.  *  to initialize global variables.
  48.  */
  49. #ifdef VM
  50. #define FLOT_MAX 7.2e75
  51. #else
  52. #if defined THINK_C || (! defined __STDC__ && defined ultrix)
  53. #define FLOT_MAX 3.4e38
  54. #else
  55. #define FLOT_MAX FLT_MAX
  56. #endif
  57. #endif
  58.  
  59. #ifdef THINK_C
  60. #define LEFTRIGHT 3
  61. #define TOPBOTTOM 12
  62. #else
  63. #define LEFTRIGHT PLOTLEFT+PLOTRIGHT
  64. #define TOPBOTTOM PLOTTOP+PLOTBOTTOM
  65. #endif
  66.  
  67. #define INDEX(rows, columns, totcols) ((rows) * (totcols) + (columns))
  68. #define BININDEX(x, y, z, xs, ys) ((xs) * (ys) * (z) + (x) * (ys) + y)
  69.  
  70. /*
  71.  * private functions
  72.  */
  73. static void bin1D(display disp, int strtpt);
  74. static void bin2D(display disp, int strtpt);
  75. /* binning for weighted plots */
  76. static void bin1D_w(display disp, int strtpt);    
  77. static void bin2D_w(display disp, int strtpt);
  78.  
  79.  
  80. display h_newDisp( graphtype_t type )
  81. {
  82.      display disp = NULL;
  83.      /*
  84.       * use this as the starting point
  85.       */
  86.      static display_t firstdisp = 
  87.      {
  88.       NULL,            /* ntuple */
  89.       0,            /* revision number */
  90.       NULL,            /* ntFile */
  91.       1,                /* dimension */
  92.       HISTOGRAM,            /* graphtype */
  93.       BOX,            /* drawtype */
  94.           {1,1,0,0,0,0,0,0},        /* flags */
  95.       NULL,            /* title */
  96.           {{0,0,0,0},        /* bin flags */
  97.        {50,-1.0,1.0,0.0,0.0},    /* bins xAxis */
  98.        {50,-1.0,1.0,0.0,0.0},    /* bins yAxis */
  99.         NULL,            /* pointer to bin data */
  100.         NULL,            /* pointer to variances */
  101.        {{0.0,0.0,0.0},{0.0,0.0,0.0},{0.0,0.0,0.0}},    /* totals */
  102.         FLOT_MAX,-FLOT_MAX,    /* binMin, binMax */
  103.         0,            /* binAlloc */
  104.         0,            /* ndata */
  105.        },                /* struct bins */
  106.       
  107.            {-1.0,1.0,NULL,
  108.         {0,1,TOPBOTTOM,PLOTBOTTOM,PLOTBOTTOM,1,0,0},
  109.          5.0,0.0,0.0,1.0,0},    /* xaxis */
  110.            {-1.0,1.0,NULL,
  111.         {0,1,LEFTRIGHT,PLOTLEFT,PLOTLEFT,1,0,0},
  112.          5.0,0.0,0.0,1.0,0},    /* yaxis */
  113.            {-1.0,1.0,NULL,
  114.         {0,1,LEFTRIGHT,PLOTLEFT,PLOTLEFT,1,0,0},
  115.          5.0,0.0,0.0,1.0,0},    /* zaxis */
  116.       
  117.       SQUARE,            /* plot symbol */
  118.       4.0,            /* plot symbol size */
  119.       SOLID,            /* line style */
  120.           {0,-1,-1,-1,-1,-1},    /* bindings to n-tuple variable */
  121.           {{0, 0},{WINDWIDTH,WINDHEIGHT}}, /* draw window */
  122.           {{LEFTMARGIN,BOTTOMMARGIN}, /* margin rectangle */
  123.           {WWMINUSLR,WHMINUSTB}},
  124.       NULL,            /* nt_cut */
  125.       NULL,            /* bin_func */
  126.       NULL,            /* plot_func */
  127.       NULL            /* bin to color transfer function */
  128.      };
  129.  
  130.      
  131.      if ( (disp = (display) malloc( sizeof(display_t)) ) == NULL )
  132.      {
  133.       h_error("Unable to allocate memory for display structure");
  134.       goto error;
  135.      }
  136.  
  137.  
  138.      memcpy(disp,&firstdisp,sizeof(display_t));
  139.  
  140.      disp->graphtype = type;
  141.  
  142.      /*
  143.       * set titles and axis labels
  144.       */
  145.      if (h_setAxisLabel(disp,XAXIS,"%x") != 0)
  146.      {
  147.       h_error("Unable to set xAxis label");
  148.       goto error;
  149.      }
  150.      if (h_setAxisLabel(disp,ZAXIS,"%z") != 0)
  151.      {
  152.       h_error("Unable to set zAxis label");
  153.       goto error;
  154.      }
  155.      if (disp->graphtype != HISTOGRAM)
  156.      {
  157.       if (h_setTitle(disp,"%t: %y vs %x") != 0)
  158.       {
  159.            h_error("Unable to set title");
  160.            goto error;
  161.       }
  162.       if (h_setAxisLabel(disp,YAXIS,"%y") != 0)
  163.       {
  164.            h_error("Unable to set yAxis label");
  165.            goto error;
  166.       }
  167.      }
  168.      else
  169.      {
  170.       if (h_setTitle(disp,"%t: %x Distribution") != 0)
  171.       {
  172.            h_error("Unable to set title");
  173.            goto error;
  174.       }
  175.       if (h_setAxisLabel(disp,YAXIS,"Entries / %dx bin") != 0)
  176.       {
  177.            h_error("Unable to set yAxis label");
  178.            goto error;
  179.       }
  180.      }      
  181.  
  182.      /*
  183.       * other details
  184.       */
  185.      switch (disp->graphtype)
  186.      {
  187.      case HISTOGRAM:
  188.       break;
  189.  
  190.      case XYPLOT:
  191.      case STRIPCHART:
  192.       disp->drawtype = POINT;
  193.       disp->dim = 2;
  194.       disp->binding.y = 1;
  195.       break;
  196.  
  197.      case COLORPLOT:
  198.       disp->dim = 2;
  199.       disp->binding.y = 1;
  200.       disp->drawtype = NONE;
  201.       break;
  202.  
  203.      case LEGOPLOT:
  204.       disp->dim = 2;
  205.       disp->binding.y = 1;
  206.       disp->drawtype = BOX;
  207.       break;
  208.  
  209.      case SCATTERPLOT:
  210.       disp->dim = 2;
  211.       disp->binding.y = 1;
  212.       disp->drawtype = POINT;
  213.       disp->plotSymbol = SOLIDSQUARE;
  214.       disp->symbolSize = 1.0;
  215.       break;
  216.      }
  217.      
  218.      return disp;
  219.  
  220.  error:
  221.      if (disp != NULL) h_freeDisp(disp);
  222.      return NULL;
  223. }
  224.  
  225.  
  226. display h_copyDisp(display olddisp)
  227. {
  228.      display disp = NULL;
  229.      func_id fid;
  230.           
  231.      if (olddisp == NULL) goto error;
  232.      
  233.      if ( (disp = (display) malloc( sizeof(display_t)) ) == NULL )
  234.      {
  235.       h_error("Unable to allocate memory for display structure");
  236.       goto error;
  237.      }
  238.      
  239.      memcpy(disp,olddisp,sizeof(display_t));
  240.  
  241.      /*
  242.       * set all pointers to NULL so we don't free something in case of error
  243.       */
  244.      disp->ntFile = NULL;
  245.      disp->bins.data = NULL;
  246.      disp->bins.variance = NULL;
  247.      disp->title = NULL;
  248.      disp->xAxis.label = NULL;
  249.      disp->yAxis.label = NULL;
  250.      disp->zAxis.label = NULL;
  251.      disp->nt_cut = NULL;
  252.      disp->bin_func = NULL;
  253.      disp->plot_func = NULL;
  254.      disp->binToColor = NULL;
  255.      
  256.      /*
  257.       * Allocate space and copy title and labels
  258.       */
  259.      if (h_setTitle(disp,olddisp->title) != 0)
  260.      {
  261.       h_error("Unable to set title");
  262.       goto error;
  263.      }
  264.      if (h_setAxisLabel(disp,XAXIS,olddisp->xAxis.label) != 0)
  265.      {
  266.       h_error("Unable to set xAxis label");
  267.       goto error;
  268.      }
  269.      if (h_setAxisLabel(disp,YAXIS,olddisp->yAxis.label) != 0)
  270.      {
  271.       h_error("Unable to set yAxis label");
  272.       goto error;
  273.      }
  274.      if (h_setAxisLabel(disp,ZAXIS,olddisp->zAxis.label) != 0)
  275.      {
  276.       h_error("Unable to set zAxis label");
  277.       goto error;
  278.      }
  279.  
  280.      /*
  281.       * Copy over cuts and plot functions
  282.       */
  283.      fid = NULL;
  284.      while ((fid = h_nextCut(olddisp,fid)))
  285.       h_addUserCut(disp, fid->name, fid->paramBlk, fid->blkSize );
  286.      fid = NULL;
  287.      while ((fid = h_nextPlotFunc(olddisp,fid)))
  288.       h_addPlotFunc(disp, fid->name, fid->paramBlk, fid->blkSize,
  289.             fid->lineStyle );
  290.  
  291.      /*
  292.       * copy ntFile if it exists.
  293.       */
  294.      if (olddisp->flags.ntByReference || olddisp->ntFile != NULL)
  295.       h_setNtByRef(disp,olddisp->flags.ntByReference,
  296.                olddisp->ntFile);
  297.      
  298.      disp->bins.flags.dirty = 0;
  299.      disp->bins.ndata = 0;
  300.      disp->bins.binAlloc = 0;
  301.      
  302.      return disp;
  303.  
  304.  error:
  305.      if (disp != NULL) h_freeDisp( disp );
  306.      return NULL;
  307. }
  308.  
  309.  
  310. int h_freeDisp( display disp )
  311. {
  312.      func_id c,next;
  313.      
  314.      if (disp == NULL) return 0;
  315.      
  316.      if (disp->bins.data != NULL)     free( disp->bins.data );
  317.      if (disp->bins.variance != NULL) free( disp->bins.variance );
  318.      if (disp->title != NULL)         free( disp->title );
  319.      if (disp->xAxis.label != NULL)   free( disp->xAxis.label );
  320.      if (disp->yAxis.label != NULL)   free( disp->yAxis.label );
  321.      if (disp->zAxis.label != NULL)   free( disp->zAxis.label );
  322.  
  323.      if (disp->ntFile != NULL)   free( disp->ntFile );
  324.      
  325.      /*
  326.       * free the lists of functions
  327.       */
  328.      c = disp->nt_cut;
  329.      while (c != NULL)
  330.      {
  331.       next = c->next;
  332.  
  333.       /* if this is standard function, free parameter block */
  334.       if (c->funcPtr == h_cut_lt || c->funcPtr == h_cut_gt || 
  335.           c->funcPtr == h_cut_le || c->funcPtr == h_cut_ge || 
  336.           c->funcPtr == h_cut_inside || c->funcPtr == h_cut_outside || 
  337.           c->funcPtr == h_cut_in_incl || c->funcPtr == h_cut_out_incl )
  338.            free(c->paramBlk);
  339.  
  340.       free(c);
  341.       c = next;
  342.      }
  343.  
  344.      c = disp->bin_func;
  345.      while (c != NULL)
  346.      {
  347.       next = c->next;
  348.       free(c);
  349.       c = next;
  350.      }
  351.  
  352.      c = disp->plot_func;
  353.      while (c != NULL)
  354.      {
  355.       next = c->next;
  356.       free(c);
  357.       c = next;
  358.      }
  359.      
  360.      free( disp );
  361.      
  362.      return 0;
  363. }
  364.  
  365. int h_bindNtuple(display disp, ntuple nt)
  366. {
  367.      char string[80];
  368.      
  369.      if (disp == NULL)
  370.       return -1;
  371.      
  372.      if (disp->ntuple == nt)
  373.       return 0;
  374.      
  375.      if (nt == NULL) 
  376.      {
  377.       /*
  378.        * user is removing reference to ntuple.
  379.        * pick up the title and labels before removing reference.
  380.        */
  381.       h_expandLabel( string, disp->title, 80, disp );
  382.       h_setTitle( disp, string );
  383.       h_expandLabel( string, disp->xAxis.label, 80, disp );
  384.       h_setAxisLabel( disp, XAXIS, string );
  385.       h_expandLabel( string, disp->yAxis.label, 80, disp );
  386.       h_setAxisLabel( disp, YAXIS, string );
  387.       h_expandLabel( string, disp->zAxis.label, 80, disp );
  388.       h_setAxisLabel( disp, ZAXIS, string );
  389.  
  390.       disp->ntuple = nt;
  391.       return 0;
  392.      }
  393.     
  394.      disp->ntuple = nt;
  395.      
  396.      disp->bins.flags.dirty = 1;
  397.      disp->nt_rev = -1;
  398.      
  399.      /*
  400.       * now, check if binding is consistent
  401.       */
  402.      /* display dimension */
  403.      if (disp->graphtype != HISTOGRAM && disp->ntuple->ndim <= 1)
  404.       return -1;
  405.      
  406.      /* axis bindings */
  407.      switch (disp->graphtype)
  408.      {
  409.      default:
  410.       if (disp->binding.y >= disp->ntuple->ndim ||
  411.           disp->binding.y < 0)
  412.            disp->binding.y = 0;
  413.      case HISTOGRAM:
  414.       if (disp->binding.x >= disp->ntuple->ndim ||
  415.           disp->binding.x < 0)
  416.            disp->binding.x = 0;
  417.      }
  418.      if (disp->binding.weight >= disp->ntuple->ndim) return -1;
  419.      
  420.      return 0;
  421. }
  422.  
  423.  
  424. int h_setNtByRef( display disp, int flag, const char *filenm )
  425. {
  426.      int i;
  427.      
  428.      if (disp == NULL) return -1;
  429.      
  430.      disp->flags.ntByReference = flag;
  431.      
  432.      if (disp->ntFile != NULL)
  433.      {
  434.       free(disp->ntFile);
  435.       disp->ntFile = NULL;
  436.      }
  437.      
  438.      if (filenm == NULL || (i=strlen(filenm)) == 0) return 0;
  439.      
  440.      if ( (disp->ntFile = (char *)malloc((i+1)*sizeof(char))) == NULL)
  441.      {
  442.       h_error("Unable to allocate space for ntFile name");
  443.       return -1;
  444.      }
  445.      strncpy(disp->ntFile,filenm,i);
  446.      
  447.      return 0;
  448. }
  449.  
  450.  
  451. int h_setLogAxis(display disp, binding_t axis, int onOff)
  452. {
  453.      if (disp == NULL) return -1;
  454.  
  455.      
  456.      switch (axis)
  457.      {
  458.      case XAXIS:
  459.       if (disp->graphtype == HISTOGRAM || 
  460.           disp->graphtype == COLORPLOT || disp->graphtype == LEGOPLOT)
  461.            return -1;
  462.       disp->xAxis.flags.log = onOff;
  463.       break;
  464.      case YAXIS:
  465.       if (disp->graphtype == COLORPLOT || disp->graphtype == LEGOPLOT)
  466.            return -1;
  467.       disp->yAxis.flags.log = onOff;
  468.       break;
  469.      case ZAXIS:
  470.       disp->zAxis.flags.log = onOff;
  471.       break;
  472.      default:
  473.       return -1;
  474.      }
  475.      return 0;
  476. }
  477.  
  478. int h_getLogAxis(display disp, binding_t axis)
  479. {
  480.      if (disp == NULL) return -1;
  481.      
  482.      switch (axis)
  483.      {
  484.      case XAXIS:
  485.       return disp->xAxis.flags.log;
  486.      case YAXIS:
  487.       return disp->yAxis.flags.log;
  488.      case ZAXIS:
  489.       return disp->zAxis.flags.log;
  490.      default:
  491.       return -1;
  492.      }
  493. }
  494.  
  495.  
  496. int h_setAutoScale(display disp, binding_t axis, int onOff)
  497. {
  498.      if (disp == NULL) return -1;
  499.      
  500.      switch (axis)
  501.      {
  502.      case XAXIS:
  503.       disp->xAxis.flags.autoScale = onOff;
  504.       break;
  505.      case YAXIS:
  506.       disp->yAxis.flags.autoScale = onOff;
  507.       break;
  508.      case ZAXIS:
  509.       disp->zAxis.flags.autoScale = onOff;
  510.       break;
  511.      default:
  512.       return -1;
  513.      }
  514.      return 0;
  515. }
  516.  
  517. int h_getAutoScale(display disp, binding_t axis)
  518. {
  519.      if (disp == NULL) return -1;
  520.      
  521.      switch (axis)
  522.      {
  523.      case XAXIS:
  524.       return disp->xAxis.flags.autoScale;
  525.      case YAXIS:
  526.       return disp->yAxis.flags.autoScale;
  527.      case ZAXIS:
  528.       return disp->zAxis.flags.autoScale;
  529.      default:
  530.       return -1;
  531.      }
  532. }
  533.      
  534.  
  535. int h_setDispType(display disp, graphtype_t type)
  536. {
  537.      if (disp == NULL) return -1;
  538.      if ( disp->ntuple == NULL ) return -1;
  539.      
  540.      disp->graphtype = type;
  541.  
  542.      switch (disp->graphtype)
  543.      {
  544.      case HISTOGRAM:
  545.       disp->dim = 1;
  546.       disp->bins.flags.dirty = 1;
  547.       break;
  548.       
  549.      case XYPLOT:
  550.      case STRIPCHART:
  551.       disp->dim = 1;
  552.       break;
  553.       
  554.      case SCATTERPLOT:
  555.      case LEGOPLOT:
  556.      case COLORPLOT:
  557.       disp->dim = 2;
  558.       disp->bins.flags.dirty = 1;
  559.       break;
  560.      }
  561.      
  562.      /*
  563.       * now, check if binding is consistent
  564.       */
  565.      /* display dimension */
  566.      if (disp->graphtype != HISTOGRAM && disp->ntuple->ndim <= 1)
  567.       return -1;
  568.      
  569.      /* axis bindings */
  570.      switch (disp->graphtype)
  571.      {
  572.      default:
  573.       if (disp->binding.y >= disp->ntuple->ndim ||
  574.           disp->binding.y < 0)
  575.            disp->binding.y = 0;
  576.      case HISTOGRAM:
  577.       if (disp->binding.x >= disp->ntuple->ndim ||
  578.           disp->binding.x < 0)
  579.            disp->binding.x = 0;
  580.      }
  581.      if (disp->binding.weight >= disp->ntuple->ndim) return -1;
  582.  
  583.      /*
  584.       * remove bins if they are useless
  585.       */
  586.      if (disp->graphtype == XYPLOT || disp->graphtype == STRIPCHART 
  587.      || disp->graphtype == SCATTERPLOT)
  588.      {
  589.       if (disp->bins.data != NULL)
  590.       {
  591.            free(disp->bins.data);
  592.            disp->bins.data = NULL;
  593.       }
  594.       if (disp->bins.variance != NULL)
  595.       {
  596.            free(disp->bins.variance);
  597.            disp->bins.variance = NULL;
  598.       }
  599.       disp->bins.binAlloc = 0;
  600.      }
  601.            
  602.      return 0;
  603. }
  604.  
  605.  
  606. int h_setDrawType(display disp, drawtype_t type)
  607. {
  608.      if (disp == NULL) return -1;
  609.      
  610.      disp->drawtype = type;
  611.      return 0;
  612. }
  613.  
  614. int h_orDrawType(display disp, drawtype_t type)
  615. {
  616.      if (disp == NULL) return -1;
  617.      
  618.      disp->drawtype |= type;
  619.      return 0;
  620. }
  621.  
  622.  
  623. int h_bind(display disp, binding_t axis, int dataDim)
  624. {
  625.      if (disp == NULL) return -1;
  626.      
  627.      if (disp->ntuple != NULL && dataDim > disp->ntuple->ndim)
  628.       return -1;
  629.      
  630.      if ( (dataDim < 0) && (axis != WEIGHT) ) return -1;
  631.      
  632.      /* note: some tolower routines are dumb, so check first */
  633.      switch (axis)
  634.      {
  635.      case XAXIS:
  636.       if (disp->binding.x != dataDim)
  637.       {
  638.            disp->binding.x = dataDim;
  639.            disp->bins.flags.dirty = 1;
  640.       }
  641.       break;
  642.      case YAXIS:
  643.       if (disp->binding.y != dataDim)
  644.       {
  645.            disp->binding.y = dataDim;
  646.            disp->bins.flags.dirty = 1;
  647.       }
  648.       break;
  649.      case ZAXIS:
  650.       if (disp->binding.z != dataDim)
  651.       {
  652.            disp->binding.z = dataDim;
  653.            disp->bins.flags.dirty = 1;
  654.       }
  655.       break;
  656.      case WEIGHT:
  657.       if (disp->binding.weight != dataDim)
  658.       {
  659.            disp->binding.weight = dataDim;
  660.            disp->bins.flags.dirty = 1;
  661.       }
  662.       break;
  663.      case XERROR:
  664.       if (disp->binding.xerror != dataDim)
  665.       {
  666.            disp->binding.xerror = dataDim;
  667.            disp->bins.flags.dirty = 1;
  668.       }
  669.       break;
  670.      case YERROR:
  671.       if (disp->binding.yerror != dataDim)
  672.       {
  673.            disp->binding.yerror = dataDim;
  674.            disp->bins.flags.dirty = 1;
  675.       }
  676.       break;
  677.      default:
  678.       return -1;
  679.      }
  680.      
  681.      return 0;
  682. }
  683.  
  684. int h_getBinding( display disp, binding_t axis )
  685. {
  686.      if (disp == NULL) return -1;
  687.      
  688.      /* note: some tolower routines are dumb, so check first */
  689.      switch (axis)
  690.      {
  691.      case XAXIS:
  692.       return disp->binding.x;
  693.       
  694.      case YAXIS:
  695.       return disp->binding.y;
  696.       
  697.      case ZAXIS:
  698.       return disp->binding.z;
  699.       
  700.      case WEIGHT:
  701.       return disp->binding.weight;
  702.       
  703.      case XERROR:
  704.       return disp->binding.xerror;
  705.       
  706.      case YERROR:
  707.       return disp->binding.yerror;
  708.       
  709.      default:
  710.       return -1;
  711.      }
  712. }
  713.  
  714.  
  715. int h_bindMany(display disp, int n, ...)
  716. {
  717.      va_list argPtr;
  718.      int i, d;
  719.      binding_t axis;
  720.      
  721.      va_start(argPtr, n);
  722.      
  723.      for (i = 0; i < n; i++) 
  724.      {
  725.       axis = va_arg(argPtr, binding_t );
  726.       d = va_arg(argPtr, int);
  727.       if (h_bind(disp,axis,d) != 0) 
  728.       {
  729.            va_end(argPtr);
  730.            return -1;
  731.       }
  732.      }
  733.      
  734.      va_end(argPtr);
  735.      
  736.      return 0;
  737. }
  738.  
  739.  
  740. int h_setBinWidth(display disp, binding_t axis, float width)
  741. {
  742.      if (disp == NULL) return -1;
  743.      if (width <= 0) return -1;
  744.      
  745.      if (disp->bins.flags.fixed && 
  746.      (disp->graphtype == HISTOGRAM || disp->graphtype == LEGOPLOT
  747.       || disp->graphtype == COLORPLOT) ) return -1;
  748.      
  749.      switch (axis)
  750.      {
  751.      case XAXIS:
  752.       disp->bins.xAxis.nBins =
  753.            ceil((disp->xAxis.high - disp->xAxis.low) / width);
  754.       disp->xAxis.high = disp->xAxis.low + disp->bins.xAxis.nBins*width;
  755.       disp->bins.xAxis.high = disp->xAxis.high;
  756.       break;
  757.  
  758.      case YAXIS:
  759.       disp->bins.yAxis.nBins =
  760.            ceil((disp->yAxis.high - disp->yAxis.low) / width);
  761.       disp->yAxis.high = disp->yAxis.low + disp->bins.yAxis.nBins*width;
  762.       disp->bins.yAxis.high = disp->yAxis.high;
  763.       break;
  764.      default:
  765.       return -1;
  766.      }
  767.      
  768.      disp->bins.flags.dirty = 1;
  769.      
  770.      return 0;
  771. }
  772.  
  773. float h_getBinWidth(display disp, binding_t axis)
  774. {
  775.      if (disp == NULL) return -1;
  776.      
  777.      switch (axis )
  778.      {
  779.      case XAXIS:
  780.       return (disp->xAxis.high - disp->xAxis.low) / disp->bins.xAxis.nBins;
  781.      case YAXIS:
  782.       return (disp->yAxis.high - disp->yAxis.low) / disp->bins.yAxis.nBins;
  783.      default:
  784.       return -1;
  785.      }
  786. }
  787.  
  788.  
  789. int h_setBinNum(display disp, binding_t axis, int n)
  790. {
  791.      if (disp == NULL || n<1) return -1;
  792.      
  793.      if (disp->bins.flags.fixed && 
  794.      (disp->graphtype == HISTOGRAM || disp->graphtype == LEGOPLOT
  795.       || disp->graphtype == COLORPLOT) ) return -1;
  796.      
  797.      switch (axis )
  798.      {
  799.      case XAXIS:
  800.       if (disp->bins.xAxis.nBins != n)
  801.       {
  802.            disp->bins.xAxis.nBins = n;
  803.            disp->bins.flags.dirty = 1;
  804.       }
  805.       break;
  806.      case YAXIS:
  807.       if (disp->bins.yAxis.nBins != n)
  808.       {
  809.            disp->bins.yAxis.nBins = n;
  810.            disp->bins.flags.dirty = 1;
  811.       }
  812.       break;
  813.      default:
  814.       return -1;
  815.      }
  816.      
  817.      return 0;
  818. }
  819.  
  820. int h_getBinNum( display disp, binding_t axis )
  821. {
  822.      if (disp == NULL) return -1;
  823.      
  824.      switch (axis )
  825.      {
  826.      case XAXIS:
  827.       return disp->bins.xAxis.nBins;
  828.       break;
  829.      case YAXIS:
  830.       return disp->bins.yAxis.nBins;
  831.       break;
  832.      default:
  833.       return -1;
  834.      }
  835. }
  836.  
  837.  
  838. int h_setRange(display disp, binding_t axis, float low, float high)
  839. {
  840.      int Auto = 0;
  841.      
  842.      if (disp->bins.flags.fixed && 
  843.      (disp->graphtype == HISTOGRAM || disp->graphtype == LEGOPLOT
  844.       || disp->graphtype == COLORPLOT) ) return -1;
  845.      
  846.      if (low >= high)
  847.      {
  848.       Auto = 1;
  849.       high = low + 1.0;
  850.      }
  851.      
  852.      if (disp == NULL) return -1;
  853.      
  854.      switch (axis )
  855.      {
  856.      case XAXIS:
  857.       disp->xAxis.low = low;
  858.       disp->xAxis.high = high;
  859.       disp->xAxis.flags.autoScale = Auto;
  860.       break;
  861.      case YAXIS:
  862.       disp->yAxis.low = low;
  863.       disp->yAxis.high = high;
  864.       disp->yAxis.flags.autoScale = Auto;
  865.       break;
  866.      case ZAXIS:
  867.       disp->zAxis.low = low;
  868.       disp->zAxis.high = high;
  869.       disp->zAxis.flags.autoScale = Auto;
  870.       break;
  871.      default:
  872.       return -1;
  873.      }
  874.      
  875.      disp->bins.flags.dirty = 1;
  876.      
  877.      return 0;
  878. }
  879.  
  880.  
  881. int h_getRange(display disp, binding_t axis, float *low, float *high)
  882. {
  883.      if (disp == NULL) return -1;
  884.      
  885.      switch (axis )
  886.      {
  887.      case XAXIS:
  888.       *low = disp->xAxis.low;
  889.       *high = disp->xAxis.high;
  890.       break;
  891.      case YAXIS:
  892.       *low = disp->yAxis.low;
  893.       *high = disp->yAxis.high;
  894.       break;
  895.      case ZAXIS:
  896.       *low = disp->zAxis.low;
  897.       *high = disp->zAxis.high;
  898.       break;
  899.      default:
  900.       return -1;
  901.      }
  902.      
  903.      return 0;
  904. }
  905.  
  906.  
  907. int h_getBinExtreme( display disp, float *min, float *max )
  908. {
  909.      if (disp == NULL) return -1;
  910.      *min = disp->bins.binMin;
  911.      *max = disp->bins.binMax;
  912.      return 0;
  913. }
  914.  
  915.  
  916. int h_dispSize( display disp )
  917. {
  918.      int i = 0;
  919.      func_id p;
  920.      
  921.      i += 4;            /* magic number */
  922.      i += (strlen(STRUCT_VERSION)/4 + 2)*4;
  923.      i += sizeof( display_t  )+8;
  924.      i += (strlen(disp->title)/4 + 2)*4;
  925.      i += (strlen(disp->ntFile)/4 + 2)*4;
  926.      if (disp->bins.flags.fixed)
  927.       i += 2 * (disp->bins.binAlloc * sizeof(float) + 4);
  928.  
  929.      i += (strlen(disp->xAxis.label)/4 + 2)*4;
  930.      i += (strlen(disp->yAxis.label)/4 + 2)*4;
  931.      i += (strlen(disp->zAxis.label)/4 + 2)*4;
  932.  
  933.      for (p=disp->nt_cut; p!=NULL; p=p->next )
  934.      {
  935.       i += sizeof(func_id_t) + 4;
  936.       i += p->blkSize * sizeof(double) + 4;
  937.      }
  938.      for (p=disp->bin_func; p!=NULL; p=p->next )
  939.      {
  940.       i += sizeof(func_id_t) + 4;
  941.       i += p->blkSize * sizeof(double) + 4;
  942.      }
  943.      for (p=disp->plot_func; p!=NULL; p=p->next )
  944.      {
  945.       i += sizeof(func_id_t) + 4;
  946.       i += p->blkSize * sizeof(double) + 4;
  947.      }
  948.      for (p=disp->binToColor; p!=NULL; p=p->next )
  949.      {
  950.       i += sizeof(func_id_t) + 4;
  951.       i += p->blkSize * sizeof(double) + 4;
  952.      }
  953.  
  954.      i += 100;            /* just in case */
  955.       
  956.      return i;
  957. }
  958.  
  959.       
  960.  
  961. int h_bin(display disp)
  962. {
  963.      int memNeeded = 1, clear=0, spt;
  964.      
  965.      if (disp == NULL) return -1;
  966.      if (disp->ntuple == NULL) return 0;
  967.      
  968.      if (disp->bins.flags.fixed) return 0;
  969.      
  970.      if (disp->ntuple->ndata == 0) 
  971.      {
  972.       disp->bins.ndata = 0;
  973.       disp->nt_rev = disp->ntuple->rev;
  974.       return 0;
  975.      }
  976.      
  977.      /* do autoscaling, if necessary */
  978.      h_autoScale( disp );
  979.      
  980.      /* scatterplots don't have bins */
  981.      if (disp->graphtype == SCATTERPLOT
  982.      || disp->graphtype == XYPLOT
  983.      || disp->graphtype == STRIPCHART)
  984.       return 0;
  985.      
  986.      /* check if re-binning is actually needed. */
  987.      if (!disp->bins.flags.dirty 
  988.      && (disp->bins.ndata == disp->ntuple->ndata)
  989.      && (disp->nt_rev == disp->ntuple->rev) 
  990.      && (disp->bins.data != NULL) )
  991.       return 0;
  992.      
  993.      /*
  994.       * if display parameters have been changed, must reset bins.
  995.       */
  996.      if (disp->bins.flags.dirty) clear = 1;
  997.      
  998.      /*
  999.       * if revision number has changed, clear bins.
  1000.       */
  1001.      if ( (disp->nt_rev == disp->ntuple->rev) ||
  1002.      (disp->bins.ndata > disp->ntuple->ndata) )
  1003.       clear = 1;
  1004.      
  1005.      /*
  1006.       * check how many bins are needed and reallocate if necessary
  1007.       */
  1008.      switch (disp->dim)
  1009.      {
  1010.      case 2:
  1011.       memNeeded *= disp->bins.yAxis.nBins;
  1012.      case 1:
  1013.       memNeeded *= disp->bins.xAxis.nBins;
  1014.      }
  1015.      if (memNeeded <= 0) return -1;
  1016.      
  1017.      if (disp->bins.binAlloc < memNeeded) 
  1018.      {
  1019.       if (disp->bins.data == NULL || disp->bins.binAlloc == 0)
  1020.       {
  1021.            disp->bins.data =
  1022.             (float *) malloc( memNeeded * sizeof(float));
  1023.            disp->bins.variance =
  1024.             (float *) malloc( memNeeded * sizeof(float));
  1025.       }
  1026.       else
  1027.       {
  1028.            disp->bins.data =
  1029.             (float *) realloc(disp->bins.data,
  1030.                       memNeeded * sizeof(float));
  1031.            disp->bins.variance =
  1032.             (float *) realloc(disp->bins.variance,
  1033.                       memNeeded * sizeof(float));
  1034.       }
  1035.       
  1036.       if ( (disp->bins.data == NULL) || (disp->bins.variance == NULL) )
  1037.       {
  1038.            free(disp->bins.data);
  1039.            free(disp->bins.variance);
  1040.            disp->bins.data = disp->bins.variance = NULL;
  1041.            disp->bins.binAlloc = 0;
  1042.            return -1;
  1043.       }
  1044.       disp->bins.binAlloc = memNeeded;
  1045.       clear = 1;
  1046.      }
  1047.      
  1048.      /*
  1049.       * clear the bins (if necessary).
  1050.       */
  1051.      if (clear) 
  1052.      {
  1053.       spt = 0;
  1054.       /* use memset for speed */
  1055.       memset((char *)disp->bins.data, (char)0, 
  1056.          memNeeded*sizeof(float) );
  1057.       memset((char *)disp->bins.variance, (char)0,
  1058.          memNeeded*sizeof(float) );
  1059.       disp->bins.binMin = FLT_MAX;
  1060.       disp->bins.binMax = -FLT_MAX;
  1061.       memset((char *)disp->bins.totals, (char)0, 
  1062.          sizeof(disp->bins.totals) );
  1063.      }
  1064.      else
  1065.       spt = disp->bins.ndata;
  1066.      
  1067.      switch (disp->dim) 
  1068.      {
  1069.      case 1:
  1070.       if (disp->binding.weight < 0) bin1D(disp, spt);
  1071.       else bin1D_w(disp, spt);
  1072.       break;
  1073.      case 2:
  1074.       if (disp->binding.weight < 0) bin2D(disp, spt);
  1075.       else bin2D_w(disp, spt);
  1076.       break;
  1077.      default:
  1078.       break;
  1079.      }
  1080.      
  1081.      disp->bins.ndata = disp->ntuple->ndata;
  1082.      disp->bins.flags.dirty = 0;  
  1083.      disp->nt_rev = disp->ntuple->rev;
  1084.      
  1085.      return 0;
  1086. }
  1087.  
  1088. void h_autoScale( display disp )
  1089. {
  1090.    /* 
  1091.     * do autoscaling of bins if requested.
  1092.     */
  1093.    if ( disp == NULL || disp->ntuple == NULL || disp->ntuple->ndata == 0)
  1094.        return;
  1095.  
  1096.  
  1097.    switch (disp->dim)
  1098.    {
  1099. #ifdef junk
  1100.    case 3:
  1101.       if (disp->zAxis.flags.autoScale)
  1102.       {
  1103.      disp->zAxis.low = disp->ntuple->nlow[disp->binding.z];
  1104.      disp->zAxis.high = disp->ntuple->nhigh[disp->binding.z];
  1105.      if (disp->graphtype == SCATTERPLOT || disp->graphtype == XYPLOT
  1106.          || disp->graphtype == STRIPCHART)
  1107.           h_adjustAxis(&(disp->zAxis.low), &(disp->zAxis.high), 
  1108.                0, disp->zAxis.flags.log);
  1109.      else
  1110.           h_adjustAxis(&(disp->zAxis.low), &(disp->zAxis.high),
  1111.                disp->zAxis.nBins, disp->zAxis.flags.log );
  1112.      disp->bins.flags.dirty = 1;
  1113.       }
  1114. #endif
  1115.    case 2:
  1116.       if (disp->yAxis.flags.autoScale)
  1117.       {
  1118.      disp->yAxis.low = disp->ntuple->nlow[disp->binding.y];
  1119.      disp->yAxis.high = disp->ntuple->nhigh[disp->binding.y];
  1120.      if (disp->yAxis.high <= disp->yAxis.low) 
  1121.           disp->yAxis.high = disp->yAxis.low + 1.0;
  1122.      
  1123.      if (disp->graphtype == SCATTERPLOT || disp->graphtype == XYPLOT
  1124.          || disp->graphtype == STRIPCHART)
  1125.           h_adjustAxis(&(disp->yAxis.low), &(disp->yAxis.high),
  1126.                0, disp->yAxis.flags.log);
  1127.      else
  1128.           h_adjustAxis(&(disp->yAxis.low), &(disp->yAxis.high),
  1129.                disp->bins.yAxis.nBins, disp->yAxis.flags.log );
  1130.      disp->bins.flags.dirty = 1;
  1131.       }
  1132.    case 1:
  1133.       if (disp->xAxis.flags.autoScale)
  1134.       {
  1135.      disp->xAxis.low = disp->ntuple->nlow[disp->binding.x];
  1136.      disp->xAxis.high = disp->ntuple->nhigh[disp->binding.x];
  1137.      if (disp->xAxis.high <= disp->xAxis.low) 
  1138.           disp->xAxis.high = disp->xAxis.low + 1.0;
  1139.  
  1140.      if (disp->graphtype == SCATTERPLOT || disp->graphtype == XYPLOT
  1141.          || disp->graphtype == STRIPCHART)
  1142.           h_adjustAxis(&(disp->xAxis.low), &(disp->xAxis.high), 
  1143.                0, disp->xAxis.flags.log );
  1144.      else
  1145.           h_adjustAxis(&(disp->xAxis.low), &(disp->xAxis.high),
  1146.                disp->bins.xAxis.nBins, disp->xAxis.flags.log );
  1147.      disp->bins.flags.dirty = 1;
  1148.       }
  1149.    }
  1150.    
  1151.    return;
  1152. }
  1153.  
  1154.  
  1155. static void bin1D(display disp, int strtpt)
  1156. {
  1157.      int bin, nXBins = disp->bins.xAxis.nBins;
  1158.      int nt_d = disp->ntuple->ndim;
  1159.      float xlow = disp->xAxis.low;
  1160.      float xhigh = disp->xAxis.high;
  1161.      float bwin = ((float) nXBins) / (xhigh - xlow);
  1162.      float *ept;
  1163.      func_id cutlist = disp->nt_cut;
  1164.      
  1165.      /*
  1166.       * set xpt to point to first nt point to accumulate.
  1167.       * set last_data to point to last point in nt data array.
  1168.       */
  1169.      float *last_data =
  1170.       &(disp->ntuple->data[INDEX(disp->ntuple->ndata,0,nt_d)]);
  1171.      float *xpt =
  1172.       &(disp->ntuple->data[INDEX(strtpt,disp->binding.x,nt_d)]);
  1173.      float *ntpt =
  1174.       &(disp->ntuple->data[INDEX(strtpt,0,nt_d)]);
  1175.      
  1176.      for ( ; xpt < last_data; xpt += nt_d, ntpt += nt_d )
  1177.      {
  1178.       if (doCuts(ntpt,cutlist)) continue;
  1179.       
  1180.       if (*xpt >= xhigh)
  1181.            disp->bins.totals[2][0] += 1.0;
  1182.       else if (*xpt < xlow)
  1183.            disp->bins.totals[0][0] += 1.0;
  1184.       else
  1185.       {
  1186.            bin = (*xpt - xlow) * bwin;
  1187.            disp->bins.data[bin]++;
  1188.            disp->bins.totals[1][0] += 1.0;
  1189.       }
  1190.      }
  1191.      
  1192.      /*
  1193.       * Look for min and max AFTER accumulating bins.
  1194.       * Minimum can only be found after all points accumulated, since
  1195.       *  first accumulation gives min. eg. all bins start at 0; first point
  1196.       *  make a bin = 1; this would be the min.
  1197.       * Also, generally faster. Usually # data points << number of bins,
  1198.       *  so much fewer compares.
  1199.       */
  1200.      disp->bins.binMin = FLT_MAX;
  1201.      disp->bins.binMax = -FLT_MAX;
  1202.      for (xpt = disp->bins.data, ept = disp->bins.variance;
  1203.       xpt<&(disp->bins.data[nXBins]);
  1204.       xpt++, ept++)
  1205.      {
  1206.       if (*xpt < disp->bins.binMin) disp->bins.binMin = *xpt;
  1207.       if (*xpt > disp->bins.binMax) disp->bins.binMax = *xpt;
  1208.       *ept = *xpt;
  1209.      }       
  1210.      return;
  1211. }
  1212.  
  1213. /*
  1214.  * binning for 1D hist. with weight. (keep separate for speed)
  1215.  */
  1216. static void bin1D_w(display disp, int strtpt)
  1217. {
  1218.      int bin, nXBins = disp->bins.xAxis.nBins;
  1219.      int nt_d = disp->ntuple->ndim;
  1220.      float xlow = disp->xAxis.low;
  1221.      float xhigh = disp->xAxis.high;
  1222.      float bwin = ((float) nXBins) / (xhigh - xlow);
  1223.      func_id cutlist = disp->nt_cut;
  1224.      
  1225.      /*
  1226.       * set xpt to point to first nt point to accumulate.
  1227.       * set last_data to point to last point in nt data array.
  1228.       */
  1229.      float *last_data =
  1230.       &(disp->ntuple->data[INDEX(disp->ntuple->ndata,0,nt_d)]);
  1231.      float *xpt =
  1232.       &(disp->ntuple->data[INDEX(strtpt,disp->binding.x,nt_d)]);
  1233.      float *wpt =
  1234.       &(disp->ntuple->data[INDEX(strtpt,disp->binding.weight,nt_d)]);
  1235.      float *ntpt = &(disp->ntuple->data[INDEX(strtpt,0,nt_d)]);
  1236.      
  1237.      for ( ; xpt < last_data; xpt += nt_d, wpt += nt_d, ntpt+=nt_d )
  1238.      {
  1239.       if (doCuts(ntpt,cutlist)) continue;
  1240.       
  1241.       if (*xpt >= xhigh) disp->bins.totals[2][0] += *wpt;
  1242.       else if (*xpt < xlow) disp->bins.totals[0][0] += *wpt;
  1243.       else
  1244.       {
  1245.            bin = (*xpt - xlow) * bwin;
  1246.            disp->bins.data[bin] += *wpt;
  1247.            disp->bins.variance[bin] += (*wpt) * (*wpt);
  1248.            disp->bins.totals[1][0] += *wpt;
  1249.       }
  1250.      }
  1251.      
  1252.      disp->bins.binMin = FLT_MAX;
  1253.      disp->bins.binMax = -FLT_MAX;
  1254.      for (xpt = disp->bins.data; xpt<&(disp->bins.data[nXBins]); xpt++)
  1255.      {
  1256.       if (*xpt < disp->bins.binMin) disp->bins.binMin = *xpt;
  1257.       if (*xpt > disp->bins.binMax) disp->bins.binMax = *xpt;
  1258.      }       
  1259.      return;
  1260. }
  1261.  
  1262.  
  1263. static void bin2D(display disp, int strtpt)
  1264. {
  1265.      int i;
  1266.      int xbin, ybin;
  1267.      int nXBins = disp->bins.xAxis.nBins, nYBins = disp->bins.yAxis.nBins;
  1268.      int nt_d = disp->ntuple->ndim;
  1269.      float xlow = disp->xAxis.low;
  1270.      float xhigh = disp->xAxis.high;
  1271.      float xbwin = ((float) nXBins) / (xhigh - xlow);
  1272.      float ylow = disp->yAxis.low;
  1273.      float yhigh = disp->yAxis.high;
  1274.      float ybwin = ((float) nYBins) / (yhigh - ylow);
  1275.      float *ept;
  1276.      func_id cutlist = disp->nt_cut;
  1277.      
  1278.      /*
  1279.       * set xpt to point to first nt point to accumulate.
  1280.       * set last_data to point beyond last point in nt data array.
  1281.       */
  1282.      float *last_data =
  1283.       &(disp->ntuple->data[INDEX(disp->ntuple->ndata,0,nt_d)]);
  1284.      float *xpt = &(disp->ntuple->data[INDEX(strtpt,disp->binding.x,nt_d)]);
  1285.      float *ypt = &(disp->ntuple->data[INDEX(strtpt,disp->binding.y,nt_d)]);
  1286.      float *ntpt = &(disp->ntuple->data[INDEX(strtpt,0,nt_d)]);
  1287.      
  1288.      for ( ; (xpt<last_data) && (ypt<last_data); 
  1289.       xpt+=nt_d, ypt+=nt_d, ntpt+=nt_d )
  1290.      {
  1291.       if (doCuts(ntpt, cutlist)) continue;
  1292.       
  1293.       if (*xpt >= xhigh)
  1294.       {
  1295.            if (*ypt >= yhigh)
  1296.             disp->bins.totals[2][2] += 1.0;
  1297.            else if (*ypt < ylow)
  1298.             disp->bins.totals[2][0] += 1.0;
  1299.            else
  1300.             disp->bins.totals[2][1] += 1.0;
  1301.       }
  1302.       else if (*xpt < xlow)
  1303.       {
  1304.            if (*ypt >= yhigh)
  1305.             disp->bins.totals[0][2] += 1.0;
  1306.            else if (*ypt < ylow)
  1307.             disp->bins.totals[0][0] += 1.0;
  1308.            else
  1309.             disp->bins.totals[0][1] += 1.0;
  1310.       }
  1311.       else
  1312.       {
  1313.            if (*ypt >= yhigh)
  1314.             disp->bins.totals[1][2] += 1.0;
  1315.            else if (*ypt < ylow)
  1316.             disp->bins.totals[1][0] += 1.0;
  1317.            else
  1318.            {
  1319.             xbin = (*xpt - xlow) * xbwin;
  1320.             ybin = (*ypt - ylow) * ybwin;
  1321.             disp->bins.data[xbin * nYBins + ybin]++; 
  1322.             disp->bins.totals[1][1] += 1.0;
  1323.            }
  1324.       }
  1325.       
  1326.      }
  1327.      
  1328.      disp->bins.binMin = FLT_MAX;
  1329.      disp->bins.binMax = -FLT_MAX;
  1330.      i = nXBins * nYBins;
  1331.      for (xpt = disp->bins.data, ept=disp->bins.variance;
  1332.       xpt<&(disp->bins.data[i]);
  1333.       xpt++, ept++)
  1334.      {
  1335.       if (*xpt < disp->bins.binMin) disp->bins.binMin = *xpt;
  1336.       if (*xpt > disp->bins.binMax) disp->bins.binMax = *xpt;
  1337.       *ept = *xpt;
  1338.      }       
  1339.      return;
  1340. }
  1341.  
  1342. static void bin2D_w(display disp, int strtpt)
  1343. {
  1344.      int i;
  1345.      int xbin, ybin;
  1346.      int nXBins = disp->bins.xAxis.nBins, nYBins = disp->bins.yAxis.nBins;
  1347.      int nt_d = disp->ntuple->ndim;
  1348.      float xlow = disp->xAxis.low;
  1349.      float xhigh = disp->xAxis.high;
  1350.      float xbwin = ((float) nXBins) / (xhigh - xlow);
  1351.      float ylow = disp->yAxis.low;
  1352.      float yhigh = disp->yAxis.high;
  1353.      float ybwin = ((float) nYBins) / (yhigh - ylow);
  1354.      func_id cutlist = disp->nt_cut;
  1355.      
  1356.      /*
  1357.       * set xpt to point to first nt point to accumulate.
  1358.       * set last_data to point to last point in nt data array.
  1359.       */
  1360.      float *last_data =
  1361.       &(disp->ntuple->data[INDEX(disp->ntuple->ndata,0,nt_d)]);
  1362.      float *xpt =
  1363.       &(disp->ntuple->data[INDEX(strtpt,disp->binding.x,nt_d)]);
  1364.      float *ypt =
  1365.       &(disp->ntuple->data[INDEX(strtpt,disp->binding.y,nt_d)]);
  1366.      float *wpt =
  1367.       &(disp->ntuple->data[INDEX(strtpt,disp->binding.weight,nt_d)]);
  1368.      float *ntpt = &(disp->ntuple->data[INDEX(strtpt,0,nt_d)]);
  1369.      
  1370.      for ( ; xpt<last_data; xpt+=nt_d, ypt+=nt_d, wpt+=nt_d, ntpt+=nt_d )
  1371.      {
  1372.       if (doCuts(ntpt, cutlist)) continue;
  1373.       
  1374.       if (*xpt >= xhigh)
  1375.       {
  1376.            if (*ypt >= yhigh)
  1377.             disp->bins.totals[2][2] += *wpt;
  1378.            else if (*ypt < ylow)
  1379.             disp->bins.totals[2][0] += *wpt;
  1380.            else
  1381.             disp->bins.totals[2][1] += *wpt;
  1382.       }
  1383.       else if (*xpt < xlow)
  1384.       {
  1385.            if (*ypt >= yhigh)
  1386.             disp->bins.totals[0][2] += *wpt;
  1387.            else if (*ypt < ylow)
  1388.             disp->bins.totals[0][0] += *wpt;
  1389.            else
  1390.             disp->bins.totals[0][1] += *wpt;
  1391.       }
  1392.       else
  1393.       {
  1394.            if (*ypt >= yhigh)
  1395.             disp->bins.totals[1][2] += *wpt;
  1396.            else if (*ypt < ylow)
  1397.             disp->bins.totals[1][0] += *wpt;
  1398.            else
  1399.            {
  1400.             xbin = (*xpt - xlow) * xbwin;
  1401.             ybin = (*ypt - ylow) * ybwin;
  1402.             disp->bins.data[xbin * nYBins + ybin] += *wpt; 
  1403.             disp->bins.variance[xbin * nYBins + ybin] += (*wpt)*(*wpt);
  1404.             disp->bins.totals[1][1] += *wpt;
  1405.            }
  1406.       }
  1407.      }
  1408.      
  1409.      disp->bins.binMin = FLT_MAX;
  1410.      disp->bins.binMax = -FLT_MAX;
  1411.      i = nXBins * nYBins;
  1412.      for (xpt = disp->bins.data; xpt<&(disp->bins.data[i]); xpt++)
  1413.      {
  1414.       if (*xpt < disp->bins.binMin) disp->bins.binMin = *xpt;
  1415.       if (*xpt > disp->bins.binMax) disp->bins.binMax = *xpt;
  1416.      }       
  1417.      return;
  1418. }
  1419.  
  1420.  
  1421. int h_ptToBin(display disp, float f, binding_t axis)
  1422. {
  1423.      float bwin = 0;
  1424.      int underBin = 0;
  1425.      
  1426.      switch (axis)
  1427.      {
  1428.      case XAXIS:
  1429.       bwin = ((float) disp->bins.xAxis.nBins) /
  1430.            (float) (disp->xAxis.high - disp->xAxis.low) ;
  1431.       underBin = disp->xAxis.low * bwin - 1;
  1432.       break;
  1433.      case YAXIS:
  1434.       bwin = ((float) disp->bins.yAxis.nBins) /
  1435.            (float) (disp->yAxis.high - disp->yAxis.low) ;
  1436.       underBin = disp->yAxis.low * bwin - 1;
  1437.       break;
  1438.      default:
  1439.       return -1;
  1440.      }      
  1441.      return (floor(f * bwin) - underBin - 1);
  1442. }
  1443.  
  1444.  
  1445. float h_binVal(display disp, ...)
  1446. {
  1447.      va_list argPtr;
  1448.      int i;
  1449. #ifndef __STDC__
  1450.      static
  1451. #endif
  1452.      int bin[3]={0,0,0};
  1453.      
  1454.      if (disp->bins.ndata == 0) return 0;
  1455.      
  1456.      va_start(argPtr, disp);
  1457.      
  1458.      for (i = 0; i < disp->dim; i++) bin[i] = va_arg(argPtr, int);
  1459.      
  1460.      va_end(argPtr);
  1461.      
  1462.      return disp->bins.data[BININDEX(bin[0], bin[1], bin[2],
  1463.                      disp->bins.xAxis.nBins, 
  1464.                      ( (disp->dim > 1) ? 
  1465.                       disp->bins.yAxis.nBins : 1) )];
  1466. }
  1467.  
  1468.  
  1469. /* 
  1470.  * conversion routines :
  1471.  */
  1472. float h_wPtTogPt(display disp, float wPt, binding_t axis)
  1473. {
  1474.      switch (axis )
  1475.      {
  1476.      case XAXIS:
  1477.       return  (((wPt - disp->marginRect.origin.x)
  1478.             / disp->marginRect.size.width)
  1479.            * (disp->xAxis.high - disp->xAxis.low) 
  1480.            + disp->xAxis.low);
  1481.       break;
  1482.       
  1483.      case YAXIS:
  1484.       return  (((wPt - disp->marginRect.origin.y)
  1485.             / disp->marginRect.size.height)
  1486.            * (disp->yAxis.high - disp->yAxis.low) 
  1487.            + disp->yAxis.low);
  1488.       break;
  1489.       
  1490.      default:
  1491.       return -1;
  1492.      }
  1493. }
  1494.  
  1495.  
  1496. float h_gPtTowPt(display disp, float gPt, binding_t axis)
  1497. {
  1498.      switch (axis )
  1499.      {
  1500.      case XAXIS:
  1501.       return (((gPt - disp->xAxis.low)
  1502.            / (disp->xAxis.high - disp->xAxis.low))
  1503.           * disp->marginRect.size.width
  1504.           + disp->marginRect.origin.x);
  1505.       break;
  1506.       
  1507.      case YAXIS:
  1508.       return (((gPt - disp->yAxis.low)
  1509.            / (disp->yAxis.high - disp->yAxis.low))
  1510.           * disp->marginRect.size.height
  1511.           + disp->marginRect.origin.y);
  1512.       break;
  1513.       
  1514.      default:
  1515.       return -1;
  1516.      }
  1517. }
  1518.  
  1519.  
  1520. int h_setDrawRect(display disp, rectangle *rect)
  1521. {
  1522.      if (disp == NULL) return -1;
  1523.      
  1524.      memcpy (&disp->drawRect, rect, sizeof(rectangle));
  1525.      return 0;
  1526. }
  1527.  
  1528. int h_setMarginRect(display disp, rectangle *rect)
  1529. {
  1530.      if (disp == NULL) return -1;
  1531.      
  1532.      memcpy (&disp->marginRect, rect, sizeof(rectangle));
  1533.      return 0;
  1534. }
  1535.  
  1536.  
  1537. int h_getDrawRect(display disp, rectangle *rect)
  1538. {
  1539.      if (disp == NULL) return -1;
  1540.      
  1541.      memcpy (rect, &disp->drawRect, sizeof(rectangle));
  1542.      
  1543.      if (rect->size.width != 0 && rect->size.height != 0)
  1544.       return 0;
  1545.      else
  1546.       return -1;
  1547. }
  1548.  
  1549. int h_getMarginRect(display disp, rectangle *rect)
  1550. {
  1551.      if (disp == NULL) return -1;
  1552.      
  1553.      memcpy (rect, &disp->marginRect, sizeof(rectangle));
  1554.      
  1555.      if (rect->size.width != 0 && rect->size.height != 0)
  1556.       return 0;
  1557.      else
  1558.       return -1;
  1559. }
  1560.  
  1561.  
  1562. int h_setTitle(display disp, const char *title)
  1563. {
  1564.      int l;
  1565.      
  1566.      if (disp == NULL) return -1;
  1567.      if (title == NULL) return -1;
  1568.      
  1569.      l = strlen(title);
  1570.      if (disp->title != NULL) free(disp->title);
  1571.      if ( (disp->title=(char *)malloc((l+1)*sizeof(char)) )==NULL)
  1572.      {
  1573.       h_error("Unable to allocate memory for title");
  1574.       return -1;
  1575.      }
  1576.      
  1577.      return strcpy(disp->title, title) ? 0 : -1;
  1578. }
  1579.  
  1580. int h_setAxisLabel(display disp, binding_t axis, const char *title)
  1581. {
  1582.      int l;
  1583.      char *p;
  1584.      
  1585.      if (disp == NULL) return -1;
  1586.      
  1587.      l = strlen(title);
  1588.      if ( (p=(char *)malloc((l+1)*sizeof(char)) )==NULL)
  1589.      {
  1590.       h_error("Unable to allocate memory for title");
  1591.       return -1;
  1592.      }
  1593.      l = strcpy(p, title) ? 0: -1;
  1594.      
  1595.      switch (axis)
  1596.      {
  1597.      case XAXIS:
  1598.       if (disp->xAxis.label != NULL) free(disp->xAxis.label);
  1599.       disp->xAxis.label = p;
  1600.       break;
  1601.      case YAXIS:
  1602.       if (disp->yAxis.label != NULL) free(disp->yAxis.label);
  1603.       disp->yAxis.label = p;
  1604.       break;
  1605.      case ZAXIS:
  1606.       if (disp->zAxis.label != NULL) free(disp->zAxis.label);
  1607.       disp->zAxis.label = p;
  1608.       break;
  1609.      default:
  1610.       free(p);
  1611.       l = -1;
  1612.      }
  1613.      
  1614.      return l;
  1615. }
  1616.  
  1617. const char *h_getAxisLabel( display disp, binding_t axis )
  1618. {
  1619.      if (disp == NULL) return NULL;
  1620.      switch (axis)
  1621.      {
  1622.      case XAXIS:
  1623.       return disp->xAxis.label;
  1624.      case YAXIS:
  1625.       return disp->yAxis.label;
  1626.      case ZAXIS:
  1627.       return disp->zAxis.label;
  1628.      default:
  1629.       return NULL;
  1630.      }
  1631. }
  1632.  
  1633.  
  1634. /*
  1635.  * Functions dealing with cuts.
  1636.  */
  1637.  
  1638. func_id h_addCut( display disp, const char *cutfunc, int cut_dim, 
  1639.          double val1, ... )
  1640. {
  1641.      va_list argPtr;
  1642.      void *fptr;
  1643.      double *parm;
  1644.      int nval;
  1645.      typedef int (*cutf)(float *,double *);
  1646.       
  1647.      
  1648.      /*
  1649.       * check that the cut variable is in ntuple.
  1650.       */
  1651.      if (cut_dim < 0 || cut_dim >= disp->ntuple->ndim)
  1652.      {
  1653.       h_error("h_addCut: Cut variable is not within ntuple\'s range.");
  1654.       return NULL;
  1655.      }
  1656.       
  1657.      /*
  1658.       * determine the function
  1659.       */
  1660.      fptr = h_fNameSrch(cutfunc);
  1661.      if (fptr==h_cut_le || 
  1662.      fptr==h_cut_lt || 
  1663.      fptr==h_cut_ge || 
  1664.      fptr==h_cut_gt )
  1665.       nval = 2;
  1666.      else if (fptr==h_cut_inside || 
  1667.           fptr==h_cut_outside || 
  1668.           fptr==h_cut_in_incl || 
  1669.           fptr==h_cut_out_incl )
  1670.       nval = 3;
  1671.      else
  1672.      {
  1673.       h_error("h_addCut: function is not supported by hippo.");
  1674.       h_error("h_addCut: use the user-function routines.");
  1675.       return NULL;
  1676.      }
  1677.  
  1678.      /* 
  1679.       * build the parameter list
  1680.       */
  1681.      if ( (parm=(double *)malloc(nval*sizeof(double))) == NULL)
  1682.      {
  1683.       h_error("Could not allocate cut parameter block.");
  1684.       return NULL;
  1685.      }
  1686.      parm[0] = (double) cut_dim;
  1687.      parm[1] = val1;
  1688.      if (nval > 2)
  1689.      {
  1690.       va_start(argPtr, val1);
  1691.       parm[2] = va_arg(argPtr, double );
  1692.       va_end(argPtr);
  1693.      }
  1694.       
  1695.      /*
  1696.       * now it looks like a user cut!
  1697.       */
  1698.      return h_addUserCut(disp, cutfunc, parm, nval );
  1699. }
  1700.  
  1701. int h_changeCut( display disp, func_id cut, double val1, ... )
  1702. {
  1703.      va_list argPtr ;
  1704.      
  1705.      double *f;
  1706.      int i;
  1707.  
  1708.      if (cut==NULL) return 0;
  1709.      
  1710.      f = (double *) cut->paramBlk;
  1711.      f[1] = val1;
  1712.      if (cut->blkSize >2)
  1713.      {
  1714.       va_start(argPtr, val1);
  1715.       for (i=2; i<cut->blkSize; i++)
  1716.            f[i] = va_arg(argPtr, double);
  1717.       va_end(argPtr);
  1718.      }
  1719.      
  1720.      /*
  1721.       * bins are now dirty.
  1722.       */
  1723.      disp->bins.flags.dirty = 1;
  1724.      
  1725.      return 0;
  1726. }
  1727.  
  1728. int h_deleteCut( display disp, func_id cut )
  1729. {
  1730.      func_id c,c_p=NULL;
  1731.      
  1732.      if (disp == NULL || cut == NULL) return 0;
  1733.      
  1734.      c = disp->nt_cut;
  1735.      
  1736.      while (c!=cut && c!=NULL) 
  1737.      {
  1738.       c_p = c;
  1739.       c = c->next;
  1740.      }
  1741.      
  1742.      if (c!=NULL)
  1743.      {
  1744.       if (c_p!=NULL) 
  1745.            c_p->next = c->next;
  1746.       else
  1747.            disp->nt_cut = c->next;
  1748.       free(c);
  1749.      }
  1750.      else
  1751.       return 0;
  1752.      
  1753.      /*
  1754.       * bins are now dirty.
  1755.       */
  1756.      disp->bins.flags.dirty = 1;
  1757.      
  1758.      return 0;
  1759. }
  1760.  
  1761. func_id h_addUserCut( display disp, const char *cutfunc, double *paramBlk,
  1762.             int nParam )
  1763. {
  1764.      func_id newcut,nextf;
  1765.      
  1766.      /*
  1767.       * allocate a new cut.
  1768.       */
  1769.      if ( (newcut = (func_id) malloc(sizeof(func_id_t))) == NULL)
  1770.      {
  1771.       h_error("Could not allocate cut structure.");
  1772.       return NULL;
  1773.      }
  1774.  
  1775.      /*
  1776.       * initialize all the fields of the new cut.
  1777.       */
  1778.      strncpy(newcut->name, cutfunc, FUNCNAMELEN);
  1779.      if ( (newcut->funcPtr = h_fNameSrch(newcut->name))
  1780.      == NULL)
  1781.      {
  1782.       h_error("h_addUserCut - function is not registered.");
  1783.       h_error("use h_funcReg");
  1784.       free(newcut);
  1785.       return NULL;
  1786.      }
  1787.  
  1788.      newcut->blkSize = nParam;
  1789.      newcut->paramBlk = (void *) paramBlk;
  1790.      
  1791.      nextf = disp->nt_cut;
  1792.      disp->nt_cut = newcut;
  1793.      newcut->next = nextf;
  1794.  
  1795.      /*
  1796.       * bins are now dirty.
  1797.       */
  1798.      disp->bins.flags.dirty = 1;
  1799.      
  1800.      return newcut;
  1801. }
  1802.  
  1803. func_id h_nextCut( display disp, func_id thiscut )
  1804. {
  1805.      if (disp == NULL) return NULL;
  1806.  
  1807.      if (thiscut == NULL) return disp->nt_cut;
  1808.  
  1809.      return thiscut->next;
  1810. }
  1811.  
  1812.  
  1813.  
  1814.  
  1815. /*
  1816.  * overplot function routines
  1817.  */
  1818. func_id h_addPlotFunc(display disp, const char *plotfunc, double *paramBlk,
  1819.               int nParam, linestyle_t ls )
  1820. {
  1821.      func_id newpfunc,nextf;
  1822.      
  1823.      /*
  1824.       * allocate a new cut.
  1825.       */
  1826.      if ( (newpfunc = (func_id) malloc(sizeof(func_id_t))) == NULL)
  1827.      {
  1828.       h_error("Could not allocate cut structure.");
  1829.       return NULL;
  1830.      }
  1831.  
  1832.      /*
  1833.       * initialize all the fields of the new cut.
  1834.       */
  1835.      strncpy(newpfunc->name, plotfunc, FUNCNAMELEN);
  1836.      if ( (newpfunc->funcPtr = h_fNameSrch(newpfunc->name))
  1837.      == NULL)
  1838.      {
  1839.       h_error("h_addPlotFunc - function is not registered.");
  1840.       h_error("use h_funcReg");
  1841.       free(newpfunc);
  1842.       return NULL;
  1843.      }
  1844.  
  1845.      newpfunc->blkSize = nParam;
  1846.      newpfunc->paramBlk = (void *)paramBlk;
  1847.      newpfunc->lineStyle = ls;
  1848.      
  1849.      nextf = disp->plot_func;
  1850.      disp->plot_func = newpfunc;
  1851.      newpfunc->next = nextf;
  1852.  
  1853.      return newpfunc;
  1854. }
  1855.  
  1856. func_id h_nextPlotFunc( display disp, func_id thispfunc )
  1857. {
  1858.      if (disp == NULL) return NULL;
  1859.  
  1860.      if (thispfunc == NULL) return disp->plot_func;
  1861.  
  1862.      return thispfunc->next;
  1863. }
  1864.  
  1865. int h_deletePlotFunc( display disp, func_id pfunc )
  1866. {
  1867.      func_id c,c_p=NULL;
  1868.      
  1869.      if (disp == NULL || pfunc == NULL) return 0;
  1870.      
  1871.      c = disp->plot_func;
  1872.      
  1873.      while (c!=pfunc && c!=NULL) 
  1874.      {
  1875.       c_p = c;
  1876.       c = c->next;
  1877.      }
  1878.      
  1879.      if (c!=NULL)
  1880.      {
  1881.       if (c_p!=NULL) 
  1882.            c_p->next = c->next;
  1883.       else
  1884.            disp->plot_func = c->next;
  1885.       free(c);
  1886.      }
  1887.      else
  1888.       return 0;
  1889.            
  1890.      return 0;
  1891. }
  1892.  
  1893.