Index: /trunk/Ohana/src/kapa2/src/DrawObjects.c
===================================================================
--- /trunk/Ohana/src/kapa2/src/DrawObjects.c	(revision 40106)
+++ /trunk/Ohana/src/kapa2/src/DrawObjects.c	(revision 40107)
@@ -1,3 +1,5 @@
 # include "Ximage.h"
+
+void DrawBars (Graphic *graphic, KapaGraphWidget *graph, Gobjects *object, int mode);
 
 # define DrawLine(X1,Y1,X2,Y2) (XDrawLine (graphic->display, graphic->window, graphic->gc, (int)(X1), (int)(Y1), (int)(X2), (int)(Y2)))
@@ -36,7 +38,6 @@
 }
 
-/* Draw a specific object in the graph */
-int DrawObjectN (Graphic *graphic, KapaGraphWidget *graph, Gobjects *object) {
-  
+void DrawLineStyle (Graphic *graphic, KapaGraphWidget *graph, Gobjects *object) {
+
   static char dot[2] = {2,3};
   static char short_dash[2] = {4,4};
@@ -85,4 +86,11 @@
     XSetForeground (graphic->display, graphic->gc, graphic->color[object[0].color]);
   }
+  return;
+}
+
+/* Draw a specific object in the graph */
+int DrawObjectN (Graphic *graphic, KapaGraphWidget *graph, Gobjects *object) {
+  
+  DrawLineStyle (graphic, graph, object);
 
   switch (object[0].style) {
@@ -92,4 +100,13 @@
     case KAPA_PLOT_HISTOGRAM:
       DrawHistogram (graphic, graph, object);
+      break;
+    case KAPA_PLOT_BARS_SOLID:
+      DrawBars (graphic, graph, object, KAPA_PLOT_BARS_SOLID);
+      break;
+    case KAPA_PLOT_BARS_OUTLINE:
+      DrawBars (graphic, graph, object, KAPA_PLOT_BARS_OUTLINE);
+      break;
+    case KAPA_PLOT_BARS_OUTFILL:
+      DrawBars (graphic, graph, object, KAPA_PLOT_BARS_OUTFILL);
       break;
     case KAPA_PLOT_POINTS:
@@ -402,4 +419,249 @@
 }
 # endif
+
+// uses object->color
+# define HISTOGRAM_SOLID(X_VALUE, Y_VALUE, DX_VAL) {			\
+  /* histogram bar corners */						\
+  double sxmin = (X_VALUE) - 0.5*(DX_VAL);				\
+  double sxmax = (X_VALUE) + 0.5*(DX_VAL);				\
+  double symin = Xaxis;							\
+  double symax = (Y_VALUE);						\
+  /* saturated values for corner coords: */				\
+  sxmin = MIN (MAX (sxmin, X0), X1);					\
+  sxmax = MIN (MAX (sxmax, X0), X1);					\
+  symin = MAX (MIN (symin, Y0), Y1);					\
+  symax = MAX (MIN (symax, Y0), Y1);					\
+  double dy = fabs(symax - symin);					\
+  double ylow = MIN(symin, symax);					\
+  FillRectangle (sxmin, ylow, (DX_VAL), dy); }
+
+// uses object->color
+# define HISTOGRAM_OUTLINE(X_VALUE, Y_VALUE, DX_VAL) {			\
+  /* histogram bar corners */						\
+  double sxmin = (X_VALUE) - 0.5*(DX_VAL);				\
+  double sxmax = (X_VALUE) + 0.5*(DX_VAL);				\
+  double symin = Xaxis;							\
+  double symax = (Y_VALUE);						\
+  /* saturated values for corner coords: */				\
+  sxmin = MIN (MAX (sxmin, X0), X1);					\
+  sxmax = MIN (MAX (sxmax, X0), X1);					\
+  symin = MAX (MIN (symin, Y0), Y1);					\
+  symax = MAX (MIN (symax, Y0), Y1);					\
+  double dy = fabs(symax - symin);					\
+  double ylow = MIN(symin, symax);					\
+  DrawRectangle (sxmin, ylow, (DX_VAL), dy); }
+
+# define HISTOGRAM_OUTFILL(X_VALUE, Y_VALUE, DX_VAL) {			\
+  /* histogram bar corners */						\
+  double sxmin = (X_VALUE) - 0.5*(DX_VAL);				\
+  double sxmax = (X_VALUE) + 0.5*(DX_VAL);				\
+  double symin = Xaxis;							\
+  double symax = (Y_VALUE);						\
+  /* saturated values for corner coords: */				\
+  sxmin = MIN (MAX (sxmin, X0), X1);					\
+  sxmax = MIN (MAX (sxmax, X0), X1);					\
+  symin = MAX (MIN (symin, Y0), Y1);					\
+  symax = MAX (MIN (symax, Y0), Y1);					\
+  double dy = fabs(symax - symin);					\
+  double ylow = MIN(symin, symax);					\
+  FillRectangle (sxmin, ylow, (DX_VAL), dy);				\
+  XSetForeground (graphic->display, graphic->gc, graphic->fore);	\
+  DrawRectangle (sxmin, ylow, (DX_VAL), dy);				\
+  XSetForeground (graphic->display, graphic->gc, graphic->color[object[0].color]); }
+
+void DrawBars (Graphic *graphic, KapaGraphWidget *graph, Gobjects *object, int mode) {
+
+  double mxi = graph[0].axis[0].dfx / (object[0].x1 - object[0].x0); // slope of the x-axis in x-pixels
+  double mxj = graph[0].axis[1].dfx / (object[0].y1 - object[0].y0); // slope of the x-axis in y-pixels (always 0 for now)
+  double myi = graph[0].axis[0].dfy / (object[0].x1 - object[0].x0); // slope of the x-axis in x-pixels (always 0 for now)
+  double myj = graph[0].axis[1].dfy / (object[0].y1 - object[0].y0); // slope of the x-axis in x-pixels
+  
+  // intercepts of axes
+  double bxi  =  graph[0].axis[0].fx - object[0].x0*graph[0].axis[0].dfx/(object[0].x1 - object[0].x0);
+  double bxj  =  -object[0].y0*graph[0].axis[1].dfx/(object[0].y1 - object[0].y0);
+  double byi  =  -object[0].x0*graph[0].axis[0].dfy/(object[0].x1 - object[0].x0);
+  double byj  =  graph[0].axis[1].fy - object[0].y0*graph[0].axis[1].dfy/(object[0].y1 - object[0].y0);
+  
+  double bx = bxi + bxj;
+  double by = byi + byj;
+  
+  // corner coords
+  double X0 = graph[0].axis[0].fx;
+  double X1 = graph[0].axis[0].fx + graph[0].axis[0].dfx;
+  double Y0 = graph[0].axis[1].fy;
+  double Y1 = graph[0].axis[1].fy + graph[0].axis[1].dfy;
+
+  /* find the first valid datapoint */
+  float *x = object[0].x;
+  float *y = object[0].y;
+  
+  /* we are drawing bars which are filled rectangles of height y[i] and width 0.5*dx
+     one point at a time
+  */
+
+  // I need to know the distance to the next and prev points to calculate dx
+  // for the first point, dx is x[1] - x[0]
+  // for the last point, dx is x[-1] - x[-2] (x[-1] is the last point)
+  // for the rest, dx is 0.5*(x[i+1] - x[i-1])
+
+  // rather than working out complex on-the-fly logic, I want to find the first and last
+  // valid point in an initial pass, the calculate the above for the remainder.
+  // or make an index vector of only valid points?
+
+  int Ngood = 0;
+  ALLOCATE_PTR (goodPoint, int, object[0].Npts);
+
+  // x = ??, y = 0: this assumes the xaxis is parallel to the plot window (myi = 0)
+  // since y runs from large on bottom to small on top, this is slightly backwards
+  float Xaxis = by + YCENTER;
+  Xaxis = MAX (Y1, MIN (Xaxis, Y0)); // MIN & MAX reversed for neg y dir
+
+  for (int i = 0; i < object[0].Npts; i++) {
+    if (!(finite(x[i]) && finite(y[i]))) continue;
+
+    // coordinate on the screen of the point:
+    double sx1r = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+    double sy1r = x[i]*myi + y[i]*myj + by + YCENTER;
+
+    if (sx1r < X0) {
+      // point to the left, skip it
+      continue;
+    }
+    if (sx1r > X1) {
+      // point to the right, skip it
+      continue;
+    }
+
+    goodPoint[Ngood] = i;
+    Ngood ++;
+  }
+    
+  if (Ngood == 0) {
+    free (goodPoint);
+    return;
+  }
+
+  // if we only have 1 point, draw bar half the width of the screen
+  // this works fine, but the auto limits for 1 value are somewhat silly
+  if (Ngood == 1) {
+    // coordinate on the screen of the point:
+    int n = goodPoint[0];
+    double sx1r = x[n]*mxi + y[n]*mxj + bx + XCENTER;
+    double sy1r = x[n]*myi + y[n]*myj + by + YCENTER;
+
+    float dx = 0.5*object->size*(X1 - X0);
+    
+    switch (mode) {
+      case KAPA_PLOT_BARS_SOLID:
+	HISTOGRAM_SOLID(sx1r, sy1r, dx);
+	break;
+      case KAPA_PLOT_BARS_OUTLINE:
+	HISTOGRAM_OUTLINE(sx1r, sy1r, dx);
+	break;
+      case KAPA_PLOT_BARS_OUTFILL:
+	HISTOGRAM_OUTFILL(sx1r, sy1r, dx);
+	break;
+      default:
+	HISTOGRAM_SOLID(sx1r, sy1r, dx);
+	break;
+    }
+
+    free (goodPoint);
+    return;
+  }
+
+  // first point:
+  {
+    int n;
+    n = goodPoint[1];
+    double sx1r = x[n]*mxi + y[n]*mxj + bx + XCENTER;
+//  double sy1r = x[n]*myi + y[n]*myj + by + YCENTER;
+
+    n = goodPoint[0];
+    double sx0r = x[n]*mxi + y[n]*mxj + bx + XCENTER;
+    double sy0r = x[n]*myi + y[n]*myj + by + YCENTER;
+
+    double dx = 0.5*object->size*(sx1r - sx0r);
+    
+    switch (mode) {
+      case KAPA_PLOT_BARS_SOLID:
+	HISTOGRAM_SOLID(sx0r, sy0r, dx);
+	break;
+      case KAPA_PLOT_BARS_OUTLINE:
+	HISTOGRAM_OUTLINE(sx0r, sy0r, dx);
+	break;
+      case KAPA_PLOT_BARS_OUTFILL:
+	HISTOGRAM_OUTFILL(sx0r, sy0r, dx);
+	break;
+      default:
+	HISTOGRAM_SOLID(sx0r, sy0r, dx);
+	break;
+    }
+  }
+
+  for (int i = 1; i < Ngood - 1; i++) {
+
+    int n;
+    n = goodPoint[i + 1];
+    double sx2r = x[n]*mxi + y[n]*mxj + bx + XCENTER;
+    double sy2r = x[n]*myi + y[n]*myj + by + YCENTER;
+
+    n = goodPoint[i - 1];
+    double sx0r = x[n]*mxi + y[n]*mxj + bx + XCENTER;
+    double sy0r = x[n]*myi + y[n]*myj + by + YCENTER;
+
+    double dx = 0.5*0.5*object->size*(sx2r - sx0r); // 2 factors of 0.5 (we want half of the average spacing)
+
+    n = goodPoint[i];
+    double sx1r = x[n]*mxi + y[n]*mxj + bx + XCENTER;
+    double sy1r = x[n]*myi + y[n]*myj + by + YCENTER;
+
+    switch (mode) {
+      case KAPA_PLOT_BARS_SOLID:
+	HISTOGRAM_SOLID(sx1r, sy1r, dx);
+	break;
+      case KAPA_PLOT_BARS_OUTLINE:
+	HISTOGRAM_OUTLINE(sx1r, sy1r, dx);
+	break;
+      case KAPA_PLOT_BARS_OUTFILL:
+	HISTOGRAM_OUTFILL(sx1r, sy1r, dx);
+	break;
+      default:
+	HISTOGRAM_SOLID(sx1r, sy1r, dx);
+	break;
+    }
+  }
+  
+  // last point:
+  {
+    int n;
+    n = goodPoint[Ngood - 1];
+    double sx1r = x[n]*mxi + y[n]*mxj + bx + XCENTER;
+    double sy1r = x[n]*myi + y[n]*myj + by + YCENTER;
+
+    n = goodPoint[Ngood - 2];
+    double sx0r = x[n]*mxi + y[n]*mxj + bx + XCENTER;
+//  double sy0r = x[n]*myi + y[n]*myj + by + YCENTER;
+
+    double dx = 0.5*object->size*(sx1r - sx0r);
+
+    switch (mode) {
+      case KAPA_PLOT_BARS_SOLID:
+	HISTOGRAM_SOLID(sx1r, sy1r, dx);
+	break;
+      case KAPA_PLOT_BARS_OUTLINE:
+	HISTOGRAM_OUTLINE(sx1r, sy1r, dx);
+	break;
+      case KAPA_PLOT_BARS_OUTFILL:
+	HISTOGRAM_OUTFILL(sx1r, sy1r, dx);
+	break;
+      default:
+	HISTOGRAM_SOLID(sx1r, sy1r, dx);
+	break;
+    }
+  }
+  free (goodPoint);
+  return;
+}
 
 /******/
