/*----------------------------------------------------------------------------
 * SciPlot	A generalized plotting widget
 *
 * Copyright (c) 1996 Robert W. McMullen
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *
 * Author: Rob McMullen <rwmcm@mail.ae.utexas.edu>
 *         http://www.ae.utexas.edu/~rwmcm
 */

#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>

#include <stdio.h>

#include "SciPlotP.h"

#define offset(field) XtOffsetOf(SciPlotRec, plot.field)
static XtResource resources[] =
{
  {XtNchartType, XtCMargin, XtRInt, sizeof(int),
    offset(ChartType), XtRImmediate, (XtPointer) XtCARTESIAN},
  {XtNdegrees, XtCBoolean, XtRBoolean, sizeof(Boolean),
    offset(Degrees), XtRImmediate, (XtPointer) True},
  {XtNdrawMajor, XtCBoolean, XtRBoolean, sizeof(Boolean),
    offset(DrawMajor), XtRImmediate, (XtPointer) True},
  {XtNdrawMajorTics, XtCBoolean, XtRBoolean, sizeof(Boolean),
    offset(DrawMajorTics), XtRImmediate, (XtPointer) True},
  {XtNdrawMinor, XtCBoolean, XtRBoolean, sizeof(Boolean),
    offset(DrawMinor), XtRImmediate, (XtPointer) True},
  {XtNdrawMinorTics, XtCBoolean, XtRBoolean, sizeof(Boolean),
    offset(DrawMinorTics), XtRImmediate, (XtPointer) True},
  {XtNmonochrome, XtCBoolean, XtRBoolean, sizeof(Boolean),
    offset(Monochrome), XtRImmediate, (XtPointer) False},
  {XtNshowLegend, XtCBoolean, XtRBoolean, sizeof(Boolean),
    offset(ShowLegend), XtRImmediate, (XtPointer) True},
  {XtNshowTitle, XtCBoolean, XtRBoolean, sizeof(Boolean),
    offset(ShowTitle), XtRImmediate, (XtPointer) True},
  {XtNshowXLabel, XtCBoolean, XtRBoolean, sizeof(Boolean),
    offset(ShowXLabel), XtRImmediate, (XtPointer) True},
  {XtNshowYLabel, XtCBoolean, XtRBoolean, sizeof(Boolean),
    offset(ShowYLabel), XtRImmediate, (XtPointer) True},
  {XtNxLabel, XtCString, XtRString, sizeof(String),
    offset(TransientXLabel), XtRString, "X Axis"},
  {XtNyLabel, XtCString, XtRString, sizeof(String),
    offset(TransientYLabel), XtRString, "Y Axis"},
  {XtNplotTitle, XtCString, XtRString, sizeof(String),
    offset(TransientPlotTitle), XtRString, "Plot"},
  {XtNmargin, XtCMargin, XtRInt, sizeof(int),
    offset(Margin), XtRImmediate, (XtPointer) 5},
  {XtNtitleMargin, XtCMargin, XtRInt, sizeof(int),
    offset(TitleMargin), XtRImmediate, (XtPointer) 16},
  {XtNlegendLineSize, XtCMargin, XtRInt, sizeof(int),
    offset(LegendLineSize), XtRImmediate, (XtPointer) 16},
  {XtNdefaultMarkerSize, XtCMargin, XtRInt, sizeof(int),
    offset(DefaultMarkerSize), XtRImmediate, (XtPointer) 3},
  {XtNlegendMargin, XtCMargin, XtRInt, sizeof(int),
    offset(LegendMargin), XtRImmediate, (XtPointer) 3},
  {XtNlegendThroughPlot, XtCBoolean, XtRBoolean, sizeof(Boolean),
    offset(LegendThroughPlot), XtRImmediate, (XtPointer) False},
  {XtNtitleFont, XtCMargin, XtRInt, sizeof(int),
    offset(TitleFont), XtRImmediate, (XtPointer) (XtFONT_HELVETICA | 24)},
  {XtNlabelFont, XtCMargin, XtRInt, sizeof(int),
    offset(LabelFont), XtRImmediate, (XtPointer) (XtFONT_TIMES | 18)},
  {XtNaxisFont, XtCMargin, XtRInt, sizeof(int),
    offset(AxisFont), XtRImmediate, (XtPointer) (XtFONT_TIMES | 10)},
  {XtNxAutoScale, XtCBoolean, XtRBoolean, sizeof(Boolean),
    offset(XAutoScale), XtRImmediate, (XtPointer) True},
  {XtNyAutoScale, XtCBoolean, XtRBoolean, sizeof(Boolean),
    offset(YAutoScale), XtRImmediate, (XtPointer) True},
  {XtNxAxisNumbers, XtCBoolean, XtRBoolean, sizeof(Boolean),
    offset(XAxisNumbers), XtRImmediate, (XtPointer) True},
  {XtNyAxisNumbers, XtCBoolean, XtRBoolean, sizeof(Boolean),
    offset(YAxisNumbers), XtRImmediate, (XtPointer) True},
  {XtNxLog, XtCBoolean, XtRBoolean, sizeof(Boolean),
    offset(XLog), XtRImmediate, (XtPointer) False},
  {XtNyLog, XtCBoolean, XtRBoolean, sizeof(Boolean),
    offset(YLog), XtRImmediate, (XtPointer) False},
  {XtNxOrigin, XtCBoolean, XtRBoolean, sizeof(Boolean),
    offset(XOrigin), XtRImmediate, (XtPointer) False},
  {XtNyOrigin, XtCBoolean, XtRBoolean, sizeof(Boolean),
    offset(YOrigin), XtRImmediate, (XtPointer) False},
  {XtNyNumbersHorizontal, XtCBoolean, XtRBoolean, sizeof(Boolean),
    offset(YNumHorz), XtRImmediate, (XtPointer) True},
};

static SciPlotFontDesc font_desc_table[] =
{
  {XtFONT_TIMES, "Times", "times", False, True},
  {XtFONT_COURIER, "Courier", "courier", True, False},
  {XtFONT_HELVETICA, "Helvetica", "helvetica", True, False},
  {XtFONT_LUCIDA, "Lucida", "lucidabright", False, False},
  {XtFONT_LUCIDASANS, "LucidaSans", "lucida", False, False},
  {XtFONT_NCSCHOOLBOOK, "NewCenturySchlbk",
    "new century schoolbook", False, True},
  {-1, NULL, NULL, False, False},
};

/*
 * Private function declarations
 */

static void Redisplay();
static void Resize();
static Boolean SetValues();
static void GetValuesHook();
static void Initialize();
static void Realize();
static void Destroy();

static void ComputeAll();
static void ComputeAllDimensions();
static void DrawAll();
static void ItemDrawAll();
static void ItemDraw();
static void EraseAll();
static void FontInit();
static int ColorStore();
static int FontStore();
static int FontnumReplace();



SciPlotClassRec sciplotClassRec =
{
  {
    /* core_class fields        */
#ifdef MOTIF
    /* superclass               */ (WidgetClass) & xmPrimitiveClassRec,
#else
    /* superclass               */ (WidgetClass) & widgetClassRec,
#endif
    /* class_name               */ "SciPlot",
    /* widget_size              */ sizeof(SciPlotRec),
    /* class_initialize         */ NULL,
    /* class_part_initialize    */ NULL,
    /* class_inited             */ False,
    /* initialize               */ Initialize,
    /* initialize_hook          */ NULL,
    /* realize                  */ Realize,
    /* actions                  */ NULL,
    /* num_actions              */ 0,
    /* resources                */ resources,
    /* num_resources            */ XtNumber(resources),
    /* xrm_class                */ NULLQUARK,
    /* compress_motion          */ True,
    /* compress_exposure        */ XtExposeCompressMultiple,
    /* compress_enterleave      */ True,
    /* visible_interest         */ True,
    /* destroy                  */ Destroy,
    /* resize                   */ Resize,
    /* expose                   */ Redisplay,
    /* set_values               */ SetValues,
    /* set_values_hook          */ NULL,
    /* set_values_almost        */ XtInheritSetValuesAlmost,
    /* get_values_hook          */ GetValuesHook,
    /* accept_focus             */ NULL,
    /* version                  */ XtVersion,
    /* callback_private         */ NULL,
    /* tm_table                 */ NULL,
    /* query_geometry           */ NULL,
    /* display_accelerator      */ XtInheritDisplayAccelerator,
    /* extension                */ NULL
  },
#ifdef MOTIF
  {
    /* primitive_class fields   */
    /* border_highlight         */ (XtWidgetProc) _XtInherit,
    /* border_unhighligh        */ (XtWidgetProc) _XtInherit,
    /* translations             */ XtInheritTranslations,
    /* arm_and_activate         */ (XtWidgetProc) _XtInherit,
    /* syn_resources            */ NULL,
    /* num_syn_resources        */ 0,
    /* extension                */ NULL
  },
#endif
  {
    /* plot_class fields        */
    /* dummy                    */ 0
    /* (some stupid compilers barf on empty structures) */
  }
};

WidgetClass sciplotWidgetClass = (WidgetClass) & sciplotClassRec;


static void
Initialize(Widget treq, Widget tnew, ArgList args, Cardinal *num)
{
  SciPlotWidget new;

  new = (SciPlotWidget) tnew;

  new->plot.plotlist = NULL;
  new->plot.alloc_plotlist = 0;
  new->plot.num_plotlist = 0;

  new->plot.alloc_drawlist = NUMPLOTITEMALLOC;
  new->plot.drawlist = (SciPlotItem *) XtCalloc(new->plot.alloc_drawlist,
    sizeof(SciPlotItem));
  new->plot.num_drawlist = 0;

  new->plot.cmap = DefaultColormap(XtDisplay(new),
    DefaultScreen(XtDisplay(new)));

  new->plot.xlabel = (char *) XtMalloc(strlen(new->plot.TransientXLabel) + 1);
  strcpy(new->plot.xlabel, new->plot.TransientXLabel);
  new->plot.ylabel = (char *) XtMalloc(strlen(new->plot.TransientYLabel) + 1);
  strcpy(new->plot.ylabel, new->plot.TransientYLabel);
  new->plot.plotTitle = (char *) XtMalloc(strlen(new->plot.TransientPlotTitle) + 1);
  strcpy(new->plot.plotTitle, new->plot.TransientPlotTitle);
  new->plot.TransientXLabel=NULL;
  new->plot.TransientYLabel=NULL;
  new->plot.TransientPlotTitle=NULL;

  new->plot.colors = NULL;
  new->plot.num_colors = 0;
  new->plot.fonts = NULL;
  new->plot.num_fonts = 0;

  new->plot.update = FALSE;
  new->plot.UserMin.x = new->plot.UserMin.y = 0.0;
  new->plot.UserMax.x = new->plot.UserMax.y = 10.0;

  new->plot.titleFont = FontStore(new, new->plot.TitleFont);
  new->plot.labelFont = FontStore(new, new->plot.LabelFont);
  new->plot.axisFont = FontStore(new, new->plot.AxisFont);
}

static void
GCInitialize(SciPlotWidget new)
{
  XGCValues values;
  XtGCMask mask;
  long colorsave;

  values.line_style = LineSolid;
  values.line_width = 0;
  values.fill_style = FillSolid;
  values.background = WhitePixelOfScreen(XtScreen(new));
  values.background = new->core.background_pixel;
  new->plot.BackgroundColor = ColorStore(new, values.background);
#ifdef MOTIF
  new->core.background_pixel = values.background;
#endif
  values.foreground = colorsave = BlackPixelOfScreen(XtScreen(new));
  new->plot.ForegroundColor = ColorStore(new, values.foreground);

  mask = GCLineStyle | GCLineWidth | GCFillStyle | GCForeground | GCBackground;
  new->plot.defaultGC = XCreateGC(XtDisplay(new),XtWindow(new), mask, &values);

  values.foreground = colorsave;
  values.line_style = LineOnOffDash;
  new->plot.dashGC = XCreateGC(XtDisplay(new),XtWindow(new), mask, &values);
}

static void
Realize(Widget aw, XtValueMask * value_mask, XSetWindowAttributes * attributes)
{
  SciPlotWidget w = (SciPlotWidget) aw;

#define	superclass	(&widgetClassRec)
  (*superclass->core_class.realize) (aw, value_mask, attributes);
#undef	superclass

  GCInitialize(w);
}

static void
Destroy(SciPlotWidget w)
{
  int i;
  SciPlotFont *pf;
  SciPlotList *p;

  XFreeGC(XtDisplay(w), w->plot.defaultGC);
  XFreeGC(XtDisplay(w), w->plot.dashGC);
  XtFree((char *) w->plot.xlabel);
  XtFree((char *) w->plot.ylabel);
  XtFree((char *) w->plot.plotTitle);

  for (i = 0; i < w->plot.num_fonts; i++) {
    pf = &w->plot.fonts[i];
    XFreeFont(XtDisplay((Widget) w), pf->font);
  }
  XtFree((char *) w->plot.fonts);

  XtFree((char *) w->plot.colors);

  for (i = 0; i < w->plot.alloc_plotlist; i++) {
    p = w->plot.plotlist + i;
    if (p->allocated > 0)
      XtFree((char *) p->data);
    if (p->legend)
      XtFree(p->legend);
  }
  if (w->plot.alloc_plotlist > 0)
    XtFree((char *) w->plot.plotlist);

  EraseAll(w);
  XtFree((char *) w->plot.drawlist);
}

static Boolean
SetValues(SciPlotWidget current, SciPlotWidget request, SciPlotWidget new,
  ArgList args, Cardinal nargs)
{
  Boolean redisplay = FALSE;

  if (current->plot.XLog != new->plot.XLog)
    redisplay = TRUE;
  else if (current->plot.YLog != new->plot.YLog)
    redisplay = TRUE;
  else if (current->plot.XOrigin != new->plot.XOrigin)
    redisplay = TRUE;
  else if (current->plot.YOrigin != new->plot.YOrigin)
    redisplay = TRUE;
  else if (current->plot.XAxisNumbers != new->plot.XAxisNumbers)
    redisplay = TRUE;
  else if (current->plot.YAxisNumbers != new->plot.YAxisNumbers)
    redisplay = TRUE;
  else if (current->plot.DrawMajor != new->plot.DrawMajor)
    redisplay = TRUE;
  else if (current->plot.DrawMajorTics != new->plot.DrawMajorTics)
    redisplay = TRUE;
  else if (current->plot.DrawMinor != new->plot.DrawMinor)
    redisplay = TRUE;
  else if (current->plot.DrawMinorTics != new->plot.DrawMinorTics)
    redisplay = TRUE;
  else if (current->plot.ChartType != new->plot.ChartType)
    redisplay = TRUE;
  else if (current->plot.Degrees != new->plot.Degrees)
    redisplay = TRUE;
  else if (current->plot.ShowLegend != new->plot.ShowLegend)
    redisplay = TRUE;
  else if (current->plot.ShowTitle != new->plot.ShowTitle)
    redisplay = TRUE;
  else if (current->plot.ShowXLabel != new->plot.ShowXLabel)
    redisplay = TRUE;
  else if (current->plot.ShowYLabel != new->plot.ShowYLabel)
    redisplay = TRUE;
  else if (current->plot.ShowTitle != new->plot.ShowTitle)
    redisplay = TRUE;
  else if (current->plot.Monochrome != new->plot.Monochrome)
    redisplay = TRUE;
  
  if (new->plot.TransientXLabel) {
    if (current->plot.TransientXLabel != new->plot.TransientXLabel ||
        strcmp(new->plot.TransientXLabel,current->plot.xlabel)!=0) {
      redisplay = TRUE;
      XtFree(current->plot.xlabel);
      new->plot.xlabel = (char *) XtMalloc(strlen(new->plot.TransientXLabel) + 1);
      strcpy(new->plot.xlabel, new->plot.TransientXLabel);
      new->plot.TransientXLabel=NULL;
    }
  }
  if (new->plot.TransientYLabel) {
    if (current->plot.TransientYLabel != new->plot.TransientYLabel ||
        strcmp(new->plot.TransientYLabel,current->plot.ylabel)!=0) {
      redisplay = TRUE;
      XtFree(current->plot.ylabel);
      new->plot.ylabel = (char *) XtMalloc(strlen(new->plot.TransientYLabel) + 1);
      strcpy(new->plot.ylabel, new->plot.TransientYLabel);
      new->plot.TransientYLabel=NULL;
    }
  }
  if (new->plot.TransientPlotTitle) {
    if (current->plot.TransientPlotTitle != new->plot.TransientPlotTitle ||
        strcmp(new->plot.TransientPlotTitle,current->plot.plotTitle)!=0) {
      redisplay = TRUE;
      XtFree(current->plot.plotTitle);
      new->plot.plotTitle = (char *) XtMalloc(strlen(new->plot.TransientPlotTitle) + 1);
      strcpy(new->plot.plotTitle, new->plot.TransientPlotTitle);
      new->plot.TransientPlotTitle=NULL;
    }
  }
  
  if (current->plot.AxisFont != new->plot.AxisFont) {
    redisplay = TRUE;
    FontnumReplace(new, new->plot.axisFont, new->plot.AxisFont);
  }
  if (current->plot.TitleFont != new->plot.TitleFont) {
    redisplay = TRUE;
    FontnumReplace(new, new->plot.titleFont, new->plot.TitleFont);
  }
  if (current->plot.LabelFont != new->plot.LabelFont) {
    redisplay = TRUE;
    FontnumReplace(new, new->plot.labelFont, new->plot.LabelFont);
  }

  new->plot.update = redisplay;

  return redisplay;
}

static void
GetValuesHook(SciPlotWidget w, ArgList args, Cardinal *num_args)
{
  int i;
  char **loc;

  for (i=0; i<*num_args; i++) {
    loc=(char **)args[i].value;
    if (strcmp(args[i].name,XtNplotTitle)==0)
      *loc=w->plot.plotTitle;
    else if (strcmp(args[i].name,XtNxLabel)==0)
      *loc=w->plot.xlabel;
    else if (strcmp(args[i].name,XtNyLabel)==0)
      *loc=w->plot.ylabel;
      
  }
}


static void
Redisplay(SciPlotWidget w)
{
  if (!XtIsRealized((Widget)w))
    return;
  
  if (w->plot.update) {
    Resize(w);
    w->plot.update = FALSE;
  }
  else {
    ItemDrawAll(w);
  }
}

static void
Resize(SciPlotWidget w)
{
  if (!XtIsRealized((Widget)w))
    return;
  
  EraseAll(w);
  ComputeAll(w);
  DrawAll(w);
}


/*
 * Private SciPlot utility functions
 */


static int 
ColorStore (SciPlotWidget w, Pixel color)
{
  w->plot.num_colors++;
  w->plot.colors = (Pixel *) XtRealloc((char *) w->plot.colors,
    sizeof(Pixel) * w->plot.num_colors);
  w->plot.colors[w->plot.num_colors - 1] = color;
  return w->plot.num_colors - 1;
}

static void 
FontnumStore (SciPlotWidget w, int fontnum, int flag)
{
  SciPlotFont *pf;
  int fontflag, sizeflag, attrflag;

  pf = &w->plot.fonts[fontnum];

  fontflag = flag & XtFONT_NAME_MASK;
  sizeflag = flag & XtFONT_SIZE_MASK;
  attrflag = flag & XtFONT_ATTRIBUTE_MASK;

  switch (fontflag) {
  case XtFONT_TIMES:
  case XtFONT_COURIER:
  case XtFONT_HELVETICA:
  case XtFONT_LUCIDA:
  case XtFONT_LUCIDASANS:
  case XtFONT_NCSCHOOLBOOK:
    break;
  default:
    fontflag = XtFONT_NAME_DEFAULT;
    break;
  }

  if (sizeflag < 1)
    sizeflag = XtFONT_SIZE_DEFAULT;

  switch (attrflag) {
  case XtFONT_BOLD:
  case XtFONT_ITALIC:
  case XtFONT_BOLD_ITALIC:
    break;
  default:
    attrflag = XtFONT_ATTRIBUTE_DEFAULT;
    break;
  }
  pf->id = flag;
  FontInit(w, pf);
}

static int 
FontnumReplace (SciPlotWidget w, int fontnum, int flag)
{
  SciPlotFont *pf;

  pf = &w->plot.fonts[fontnum];
  XFreeFont(XtDisplay(w), pf->font);

  FontnumStore(w, fontnum, flag);

  return fontnum;
}

static int 
FontStore (SciPlotWidget w, int flag)
{
  int fontnum;

  w->plot.num_fonts++;
  w->plot.fonts = (SciPlotFont *) XtRealloc((char *) w->plot.fonts,
    sizeof(SciPlotFont) * w->plot.num_fonts);
  fontnum = w->plot.num_fonts - 1;

  FontnumStore(w, fontnum, flag);

  return fontnum;
}

static SciPlotFontDesc *
FontDescLookup (int flag)
{
  SciPlotFontDesc *pfd;

  pfd = font_desc_table;
  while (pfd->flag >= 0) {
#ifdef DEBUG_SCIPLOT
    printf("checking if %d == %d (font %s)\n",
      flag & XtFONT_NAME_MASK, pfd->flag, pfd->PostScript);
#endif
    if ((flag & XtFONT_NAME_MASK) == pfd->flag)
      return pfd;
    pfd++;
  }
  return NULL;
}


static void 
FontnumPostScriptString (SciPlotWidget w, int fontnum, char *str)
{
  char temp[128];
  int flag, bold, italic;
  SciPlotFontDesc *pfd;

  flag = w->plot.fonts[fontnum].id;
  pfd = FontDescLookup(flag);
  if (pfd) {
    strcpy(temp, pfd->PostScript);
    bold = False;
    italic = False;
    if (flag & XtFONT_BOLD) {
      bold = True;
      strcat(temp, "-Bold");
    }
    if (flag & XtFONT_ITALIC) {
      italic = True;
      if (!bold)
	strcat(temp, "-");
      if (pfd->PSUsesOblique)
	strcat(temp, "Oblique");
      else
	strcat(temp, "Italic");
    }
    if (!bold && !italic && pfd->PSUsesRoman) {
      strcat(temp, "-Roman");
    }

    sprintf(str, "/%s findfont %d scalefont",
      temp,
      (flag & XtFONT_SIZE_MASK));
  }
  else
    sprintf(str, "/Courier findfond 10 scalefont");
}

static void 
FontX11String (int flag, char *str)
{
  SciPlotFontDesc *pfd;

  pfd = FontDescLookup(flag);
  if (pfd) {
    sprintf(str, "-*-%s-%s-%s-*-*-%d-*-*-*-*-*-*-*",
      pfd->X11,
      (flag & XtFONT_BOLD ? "bold" : "medium"),
      (flag & XtFONT_ITALIC ? (pfd->PSUsesOblique ? "o" : "i") : "r"),
      (flag & XtFONT_SIZE_MASK));
  }
  else
    sprintf(str, "fixed");
#ifdef DEBUG_SCIPLOT
  printf("font string=%s\n", str);
#endif
}

static void 
FontInit (SciPlotWidget w, SciPlotFont *pf)
{
  char str[256], **list;
  int num;

  FontX11String(pf->id, str);
  list = XListFonts(XtDisplay(w), str, 100, &num);
#ifdef DEBUG_SCIPLOT
  if (1) {
    int i;

    i = 0;
    while (i < num) {
      printf("Found font: %s\n", list[i]);
      i++;
    }
  }
#endif
  if (num <= 0) {
    pf->id &= ~XtFONT_ATTRIBUTE_MASK;
    pf->id |= XtFONT_ATTRIBUTE_DEFAULT;
    FontX11String(pf->id, str);
    list = XListFonts(XtDisplay(w), str, 100, &num);
#ifdef DEBUG_SCIPLOT
    if (1) {
      int i;

      i = 0;
      while (i < num) {
	printf("Attr reset: found: %s\n", list[i]);
	i++;
      }
    }
#endif
  }
  if (num <= 0) {
    pf->id &= ~XtFONT_NAME_MASK;
    pf->id |= XtFONT_NAME_DEFAULT;
    FontX11String(pf->id, str);
    list = XListFonts(XtDisplay(w), str, 100, &num);
#ifdef DEBUG_SCIPLOT
    if (1) {
      int i;

      i = 0;
      while (i < num) {
	printf("Name reset: found: %s\n", list[i]);
	i++;
      }
    }
#endif
  }
  if (num <= 0) {
    pf->id &= ~XtFONT_SIZE_MASK;
    pf->id |= XtFONT_SIZE_DEFAULT;
    FontX11String(pf->id, str);
    list = XListFonts(XtDisplay(w), str, 100, &num);
#ifdef DEBUG_SCIPLOT
    if (1) {
      int i;

      i = 0;
      while (i < num) {
	printf("Size reset: found: %s\n", list[i]);
	i++;
      }
    }
#endif
  }
  if (num <= 0)
    strcpy(str, "fixed");
  else
    XFreeFontNames(list);
  pf->font = XLoadQueryFont(XtDisplay(w), str);
}

static XFontStruct *
FontFromFontnum (SciPlotWidget w, int fontnum)
{
  XFontStruct *f;

  if (fontnum >= w->plot.num_fonts)
    fontnum = 0;
  f = w->plot.fonts[fontnum].font;
  return f;
}

static real
FontHeight(XFontStruct *f)
{
  return (real) (f->max_bounds.ascent + f->max_bounds.descent);
}

static real
FontnumHeight(SciPlotWidget w, int fontnum)
{
  XFontStruct *f;

  f = FontFromFontnum(w, fontnum);
  return FontHeight(f);
}

static real
FontDescent(XFontStruct *f)
{
  return (real) (f->max_bounds.descent);
}

static real
FontnumDescent(SciPlotWidget w, int fontnum)
{
  XFontStruct *f;

  f = FontFromFontnum(w, fontnum);
  return FontDescent(f);
}

static real
FontAscent(XFontStruct *f)
{
  return (real) (f->max_bounds.ascent);
}

static real
FontnumAscent(SciPlotWidget w, int fontnum)
{
  XFontStruct *f;

  f = FontFromFontnum(w, fontnum);
  return FontAscent(f);
}

static real
FontTextWidth(XFontStruct *f, char *c)
{
  return (real) XTextWidth(f, c, strlen(c));
}

static real
FontnumTextWidth(SciPlotWidget w, int fontnum, char *c)
{
  XFontStruct *f;

  f = FontFromFontnum(w, fontnum);
  return FontTextWidth(f, c);
}


/*
 * Private List functions
 */

static int 
_ListNew (SciPlotWidget w)
{
  int index;
  SciPlotList *p;
  Boolean found;

/* First check to see if there is any free space in the index */
  found = FALSE;
  for (index = 0; index < w->plot.num_plotlist; index++) {
    p = w->plot.plotlist + index;
    if (!p->used) {
      found = TRUE;
      break;
    }
  }

/* If no space is found, increase the size of the index */
  if (!found) {
    w->plot.num_plotlist++;
    if (w->plot.alloc_plotlist == 0) {
      w->plot.alloc_plotlist = NUMPLOTLINEALLOC;
      w->plot.plotlist = (SciPlotList *) XtCalloc(w->plot.alloc_plotlist, sizeof(SciPlotList));
      if (!w->plot.plotlist) {
	printf("Can't calloc memory for SciPlotList\n");
	exit(1);
      }
      w->plot.alloc_plotlist = NUMPLOTLINEALLOC;
    }
    else if (w->plot.num_plotlist > w->plot.alloc_plotlist) {
      w->plot.alloc_plotlist += NUMPLOTLINEALLOC;
      w->plot.plotlist = (SciPlotList *) XtRealloc((char *) w->plot.plotlist,
	w->plot.alloc_plotlist * sizeof(SciPlotList));
      if (!w->plot.plotlist) {
	printf("Can't realloc memory for SciPlotList\n");
	exit(1);
      }
    }
    index = w->plot.num_plotlist - 1;
    p = w->plot.plotlist + index;
  }

  p->LineStyle = p->LineColor = p->PointStyle = p->PointColor = 0;
  p->number = p->allocated = 0;
  p->data = NULL;
  p->legend = NULL;
  p->draw = p->used = TRUE;
  p->markersize = (real) w->plot.DefaultMarkerSize;
  return index;
}

static void 
_ListDelete (SciPlotList *p)
{
  p->draw = p->used = FALSE;
  p->number = p->allocated = 0;
  if (p->data)
    XtFree((char *) p->data);
  p->data = NULL;
  if (p->legend)
    XtFree((char *) p->legend);
  p->legend = NULL;
}

static SciPlotList *
_ListFind (SciPlotWidget w, int id)
{
  SciPlotList *p;

  if ((id >= 0) && (id < w->plot.num_plotlist)) {
    p = w->plot.plotlist + id;
    if (p->used)
      return p;
  }
  return NULL;
}

static void 
_ListSetStyle (SciPlotList *p, int pcolor, int pstyle, int lcolor, int lstyle)
{
/* Note!  Do checks in here later on... */

  if (lstyle >= 0)
    p->LineStyle = lstyle;
  if (lcolor >= 0)
    p->LineColor = lcolor;
  if (pstyle >= 0)
    p->PointStyle = pstyle;
  if (pcolor >= 0)
    p->PointColor = pcolor;
}

static void 
_ListSetLegend (SciPlotList *p, char *legend)
{
/* Note!  Do checks in here later on... */

  p->legend = (char *) XtMalloc(strlen(legend) + 1);
  strcpy(p->legend, legend);
}

static void 
_ListAllocData (SciPlotList *p, int num)
{
  if (p->data) {
    XtFree((char *) p->data);
    p->allocated = 0;
  }
  p->allocated = num + NUMPLOTDATAEXTRA;
  p->data = (realpair *) XtCalloc(p->allocated, sizeof(realpair));
  if (!p->data) {
    p->number = p->allocated = 0;
  }
}

static void 
_ListReallocData (SciPlotList *p, int more)
{
  if (!p->data) {
    _ListAllocData(p, more);
  }
  else if (p->number + more > p->allocated) {
    p->allocated += more + NUMPLOTDATAEXTRA;
    p->data = (realpair *) XtRealloc((char *) p->data, p->allocated * sizeof(realpair));
    if (!p->data) {
      p->number = p->allocated = 0;
    }
  }

}

static void 
_ListAddReal (SciPlotList *p, int num, real *xlist, real *ylist)
{
  int i;

  _ListReallocData(p, num);
  if (p->data) {
    for (i = 0; i < num; i++) {
      p->data[i + p->number].x = xlist[i];
      p->data[i + p->number].y = ylist[i];
    }
    p->number += num;
  }
}

static void 
_ListAddFloat (SciPlotList *p, int num, float *xlist, float *ylist)
{
  int i;

  _ListReallocData(p, num);
  if (p->data) {
    for (i = 0; i < num; i++) {
      p->data[i + p->number].x = xlist[i];
      p->data[i + p->number].y = ylist[i];
    }
    p->number += num;
  }
}

static void 
_ListAddDouble (SciPlotList *p, int num, double *xlist, double *ylist)
{
  int i;

  _ListReallocData(p, num);
  if (p->data) {
    for (i = 0; i < num; i++) {
      p->data[i + p->number].x = xlist[i];
      p->data[i + p->number].y = ylist[i];
    }
    p->number += num;
  }
}

static void
_ListSetReal(SciPlotList *p, int num, real *xlist, real *ylist)
{
  if ((!p->data) || (p->allocated < num))
    _ListAllocData(p, num);
  p->number = 0;
  _ListAddReal(p, num, xlist, ylist);
}

static void 
_ListSetFloat (SciPlotList *p, int num, float *xlist, float *ylist)
{
  if ((!p->data) || (p->allocated < num))
    _ListAllocData(p, num);
  p->number = 0;
  _ListAddFloat(p, num, xlist, ylist);
}

static void 
_ListSetDouble (SciPlotList *p, int num, double *xlist, double *ylist)
{
  if ((!p->data) || (p->allocated < num))
    _ListAllocData(p, num);
  p->number = 0;
  _ListAddDouble(p, num, xlist, ylist);
}


/*
 * Private SciPlot functions
 */


/* 
 * The following vertical text drawing routine uses the "Fill Stippled" idea
 * found in xvertext-5.0, by Alan Richardson (mppa3@syma.sussex.ac.uk).
 * 
 * The following code is my interpretation of his idea, including some
 * hacked together excerpts from his source.  The credit for the clever bits
 * belongs to him.
 * 
 * To be complete, portions of the subroutine XDrawVString are
 * Copyright (c) 1993 Alan Richardson (mppa3@syma.sussex.ac.uk)
 */
static void 
XDrawVString (Display *display, Window win, GC gc, int x, int y, char *str, int len, XFontStruct *f)
{
  XImage *before, *after;
  char *dest, *source;
  int xloop, yloop, xdest, ydest;
  Pixmap pix, rotpix;
  int width, height;
  GC drawGC;

  width = (int) FontTextWidth(f, str);
  height = (int) FontHeight(f);

  pix = XCreatePixmap(display, win, width, height, 1);
  rotpix = XCreatePixmap(display, win, height, width, 1);

  drawGC = XCreateGC(display, pix, 0L, NULL);
  XSetBackground(display, drawGC, 0);
  XSetFont(display, drawGC, f->fid);
  XSetForeground(display, drawGC, 0);
  XFillRectangle(display, pix, drawGC, 0, 0, width, height);
  XFillRectangle(display, rotpix, drawGC, 0, 0, height, width);
  XSetForeground(display, drawGC, 1);

  XDrawImageString(display, pix, drawGC, 0, (int) FontAscent(f),
    str, strlen(str));

  source = (char *) XtCalloc((((width + 7) / 8) * height), 1);
  before = XCreateImage(display, DefaultVisual(display, DefaultScreen(display)),
    1, XYPixmap, 0, source, width, height, 8, 0);
  before->byte_order = before->bitmap_bit_order = MSBFirst;
  XGetSubImage(display, pix, 0, 0, width, height, 1L, XYPixmap, before, 0, 0);
  source = (char *) XtCalloc((((height + 7) / 8) * width), 1);
  after = XCreateImage(display, DefaultVisual(display, DefaultScreen(display)),
    1, XYPixmap, 0, source, height, width, 8, 0);
  after->byte_order = after->bitmap_bit_order = MSBFirst;

  for (yloop = 0; yloop < height; yloop++) {
    for (xloop = 0; xloop < width; xloop++) {
      source = before->data + (xloop / 8) +
	(yloop * before->bytes_per_line);
      if (*source & (128 >> (xloop % 8))) {
	dest = after->data + (yloop / 8) +
	  ((width - 1 - xloop) * after->bytes_per_line);
	*dest |= (128 >> (yloop % 8));
      }
    }
  }

#ifdef DEBUG_SCIPLOT_VTEXT
  if (1) {
    char sourcebit;

    for (yloop = 0; yloop < before->height; yloop++) {
      for (xloop = 0; xloop < before->width; xloop++) {
	source = before->data + (xloop / 8) +
	  (yloop * before->bytes_per_line);
	sourcebit = *source & (128 >> (xloop % 8));
	if (sourcebit)
	  putchar('X');
	else
	  putchar('.');
      }
      putchar('\n');
    }

    for (yloop = 0; yloop < after->height; yloop++) {
      for (xloop = 0; xloop < after->width; xloop++) {
	source = after->data + (xloop / 8) +
	  (yloop * after->bytes_per_line);
	sourcebit = *source & (128 >> (xloop % 8));
	if (sourcebit)
	  putchar('X');
	else
	  putchar('.');
      }
      putchar('\n');
    }
  }
#endif

  xdest = x - (int) FontAscent(f);
  if (xdest < 0)
    xdest = 0;
  ydest = y - width;

  XPutImage(display, rotpix, drawGC, after, 0, 0, 0, 0,
    after->width, after->height);

  XSetFillStyle(display, gc, FillStippled);
  XSetStipple(display, gc, rotpix);
  XSetTSOrigin(display, gc, xdest, ydest);
  XFillRectangle(display, win, gc, xdest, ydest, after->width, after->height);
  XSetFillStyle(display, gc, FillSolid);

  XFreeGC(display, drawGC);
  XDestroyImage(before);
  XDestroyImage(after);
  XFreePixmap(display, pix);
  XFreePixmap(display, rotpix);

/* Note that it appears that there is a memory leak here, but XDestroyImage
 * frees the image data that is XtCalloc'ed
 */

}

static char dots[] =
{2, 1, 1};
static char widedots[] =
{2, 1, 4};

static GC 
ItemGetGC (SciPlotWidget w, SciPlotItem *item)
{
  GC gc;
  short color;

  switch (item->kind.any.style) {
  case XtLINE_SOLID:
    gc = w->plot.defaultGC;
    break;
  case XtLINE_DOTTED:
    XSetDashes(XtDisplay(w), w->plot.dashGC, 0, &dots[1],
      (int) dots[0]);
    gc = w->plot.dashGC;
    break;
  case XtLINE_WIDEDOT:
    XSetDashes(XtDisplay(w), w->plot.dashGC, 0, &widedots[1],
      (int) widedots[0]);
    gc = w->plot.dashGC;
    break;
  default:
    return NULL;
    break;
  }
  if (w->plot.Monochrome)
    if (item->kind.any.color > 0)
      color = w->plot.ForegroundColor;
    else
      color = w->plot.BackgroundColor;
  else if (item->kind.any.color >= w->plot.num_colors)
    color = w->plot.ForegroundColor;
  else if (item->kind.any.color <= 0)
    color = w->plot.BackgroundColor;
  else
    color = item->kind.any.color;
  XSetForeground(XtDisplay(w), gc, w->plot.colors[color]);
  return gc;
}

static GC 
ItemGetFontGC (SciPlotWidget w, SciPlotItem *item)
{
  GC gc;
  short color, fontnum;

  gc = w->plot.dashGC;
  if (w->plot.Monochrome)
    if (item->kind.any.color > 0)
      color = w->plot.ForegroundColor;
    else
      color = w->plot.BackgroundColor;
  else if (item->kind.any.color >= w->plot.num_colors)
    color = w->plot.ForegroundColor;
  else if (item->kind.any.color <= 0)
    color = w->plot.BackgroundColor;
  else
    color = item->kind.any.color;
  XSetForeground(XtDisplay(w), gc, w->plot.colors[color]);
  if (item->kind.text.font >= w->plot.num_fonts)
    fontnum = 0;
  else
    fontnum = item->kind.text.font;

/*
 * fontnum==0 hack:  0 is supposed to be the default font, but the program
 * can't seem to get the default font ID from the GC for some reason.  So,
 * use a different GC where the default font still exists.
 */
  XSetFont(XtDisplay(w), gc, w->plot.fonts[fontnum].font->fid);
  return gc;
}

static void 
ItemDraw (SciPlotWidget w, SciPlotItem *item)
{
  XPoint point[8];
  XSegment seg;
  XRectangle rect;
  int i;
  GC gc;

  if (!XtIsRealized((Widget) w))
    return;
  if ((item->type > SciPlotStartTextTypes) && (item->type < SciPlotEndTextTypes))
    gc = ItemGetFontGC(w, item);
  else
    gc = ItemGetGC(w, item);
  if (!gc)
    return;
  switch (item->type) {
  case SciPlotLine:
    seg.x1 = (short) item->kind.line.x1;
    seg.y1 = (short) item->kind.line.y1;
    seg.x2 = (short) item->kind.line.x2;
    seg.y2 = (short) item->kind.line.y2;
    XDrawSegments(XtDisplay(w), XtWindow(w), gc,
      &seg, 1);
    break;
  case SciPlotRect:
    XDrawRectangle(XtDisplay(w), XtWindow(w), gc,
      (int) (item->kind.rect.x),
      (int) (item->kind.rect.y),
      (unsigned int) (item->kind.rect.w),
      (unsigned int) (item->kind.rect.h));
    break;
  case SciPlotFRect:
    XFillRectangle(XtDisplay(w), XtWindow(w), gc,
      (int) (item->kind.rect.x),
      (int) (item->kind.rect.y),
      (unsigned int) (item->kind.rect.w),
      (unsigned int) (item->kind.rect.h));
    XDrawRectangle(XtDisplay(w), XtWindow(w), gc,
      (int) (item->kind.rect.x),
      (int) (item->kind.rect.y),
      (unsigned int) (item->kind.rect.w),
      (unsigned int) (item->kind.rect.h));
    break;
  case SciPlotPoly:
    i = 0;
    while (i < item->kind.poly.count) {
      point[i].x = (int) item->kind.poly.x[i];
      point[i].y = (int) item->kind.poly.y[i];
      i++;
    }
    point[i].x = (int) item->kind.poly.x[0];
    point[i].y = (int) item->kind.poly.y[0];
    XDrawLines(XtDisplay(w), XtWindow(w), gc,
      point, i + 1, CoordModeOrigin);
    break;
  case SciPlotFPoly:
    i = 0;
    while (i < item->kind.poly.count) {
      point[i].x = (int) item->kind.poly.x[i];
      point[i].y = (int) item->kind.poly.y[i];
      i++;
    }
    point[i].x = (int) item->kind.poly.x[0];
    point[i].y = (int) item->kind.poly.y[0];
    XFillPolygon(XtDisplay(w), XtWindow(w), gc,
      point, i + 1, Complex, CoordModeOrigin);
    XDrawLines(XtDisplay(w), XtWindow(w), gc,
      point, i + 1, CoordModeOrigin);
    break;
  case SciPlotCircle:
    XDrawArc(XtDisplay(w), XtWindow(w), gc,
      (int) (item->kind.circ.x - item->kind.circ.r),
      (int) (item->kind.circ.y - item->kind.circ.r),
      (unsigned int) (item->kind.circ.r * 2),
      (unsigned int) (item->kind.circ.r * 2),
      0 * 64, 360 * 64);
    break;
  case SciPlotFCircle:
    XFillArc(XtDisplay(w), XtWindow(w), gc,
      (int) (item->kind.circ.x - item->kind.circ.r),
      (int) (item->kind.circ.y - item->kind.circ.r),
      (unsigned int) (item->kind.circ.r * 2),
      (unsigned int) (item->kind.circ.r * 2),
      0 * 64, 360 * 64);
    break;
  case SciPlotText:
    XDrawString(XtDisplay(w), XtWindow(w), gc,
      (int) (item->kind.text.x), (int) (item->kind.text.y),
      item->kind.text.text,
      (int) item->kind.text.length);
    break;
  case SciPlotVText:
    XDrawVString(XtDisplay(w), XtWindow(w), gc,
      (int) (item->kind.text.x), (int) (item->kind.text.y),
      item->kind.text.text,
      (int) item->kind.text.length,
      FontFromFontnum(w, item->kind.text.font));
    break;
  case SciPlotClipRegion:
    rect.x = (short) item->kind.line.x1;
    rect.y = (short) item->kind.line.y1;
    rect.width = (short) item->kind.line.x2;
    rect.height = (short) item->kind.line.y2;
    XSetClipRectangles(XtDisplay(w), w->plot.dashGC, 0, 0, &rect, 1, Unsorted);
    XSetClipRectangles(XtDisplay(w), w->plot.defaultGC, 0, 0, &rect, 1, Unsorted);
    break;
  case SciPlotClipClear:
    XSetClipMask(XtDisplay(w), w->plot.dashGC, None);
    XSetClipMask(XtDisplay(w), w->plot.defaultGC, None);
    break;
  default:
    break;
  }
}

static void 
ItemDrawAll (SciPlotWidget w)
{
  SciPlotItem *item;
  int i;

  if (!XtIsRealized((Widget) w))
    return;
  item = w->plot.drawlist;
  i = 0;
  while (i < w->plot.num_drawlist) {
    ItemDraw(w, item);
    i++;
    item++;
  }
}



/*
 * PostScript (r) functions ------------------------------------------------
 *
 */
typedef struct {
  char *command;
  char *prolog;
} PScommands;

static PScommands psc[] =
{
  {"ma", "moveto"},
  {"da", "lineto stroke newpath"},
  {"la", "lineto"},
  {"poly", "closepath stroke newpath"},
  {"fpoly", "closepath fill newpath"},
  {"box", "1 index 0 rlineto 0 exch rlineto neg 0 rlineto closepath stroke newpath"},
  {"fbox", "1 index 0 rlineto 0 exch rlineto neg 0 rlineto closepath fill newpath"},
  {"clipbox", "gsave 1 index 0 rlineto 0 exch rlineto neg 0 rlineto closepath clip newpath"},
  {"unclip", "grestore newpath"},
  {"cr", "0 360 arc stroke newpath"},
  {"fcr", "0 360 arc fill newpath"},
  {"vma", "gsave moveto 90 rotate"},
  {"norm", "grestore"},
  {"solid", "[] 0 setdash"},
  {"dot", "[.25 2] 0 setdash"},
  {"widedot", "[.25 8] 0 setdash"},
  {"rgb", "setrgbcolor"},
  {NULL, NULL}
};

enum PSenums {
  PSmoveto, PSlineto,
  PSpolyline, PSendpoly, PSendfill,
  PSbox, PSfbox,
  PSclipbox, PSunclip,
  PScircle, PSfcircle,
  PSvmoveto, PSnormal,
  PSsolid, PSdot, PSwidedot,
  PSrgb
};

static void 
ItemPSDrawAll (SciPlotWidget w, FILE *fd, double yflip, Boolean usecolor)
{
  int i, loopcount;
  SciPlotItem *item;
  XcmsColor currentcolor;
  int previousfont, previousline, currentfont, currentline, previouscolor;

  item = w->plot.drawlist;
  loopcount = 0;
  previousfont = 0;
  previouscolor = -1;
  previousline = XtLINE_SOLID;
  while (loopcount < w->plot.num_drawlist) {

/* 2 switch blocks:  1st sets up defaults, 2nd actually draws things. */
    currentline = previousline;
    currentfont = previousfont;
    switch (item->type) {
    case SciPlotLine:
    case SciPlotCircle:
      currentline = item->kind.any.style;
      break;
    default:
      break;
    }
    if (currentline != XtLINE_NONE) {
      if (currentline != previousline) {
	switch (item->kind.any.style) {
	case XtLINE_SOLID:
	  fprintf(fd, "%s ", psc[PSsolid].command);
	  break;
	case XtLINE_DOTTED:
	  fprintf(fd, "%s ", psc[PSdot].command);
	  break;
	case XtLINE_WIDEDOT:
	  fprintf(fd, "%s ", psc[PSwidedot].command);
	  break;
	}
	previousline = currentline;
      }

      if (usecolor && item->kind.any.color != previouscolor) {
        
          /* Get Pixel index */
        currentcolor.pixel = w->plot.colors[item->kind.any.color];
          /* Get RGBi components [0.0,1.0] */
        XcmsQueryColor( XtDisplay(w), w->plot.cmap, &currentcolor,
          XcmsRGBiFormat );
          /* output PostScript command */
        fprintf(fd, "%f %f %f %s ", currentcolor.spec.RGBi.red,
          currentcolor.spec.RGBi.green, currentcolor.spec.RGBi.blue,
          psc[PSrgb].command);

        previouscolor=item->kind.any.color;
        
      }

      switch (item->type) {
      case SciPlotLine:
	fprintf(fd, "%.2f %.2f %s %.2f %.2f %s\n",
	  item->kind.line.x1, yflip - item->kind.line.y1,
	  psc[PSmoveto].command,
	  item->kind.line.x2, yflip - item->kind.line.y2,
	  psc[PSlineto].command);
	break;
      case SciPlotRect:
	fprintf(fd, "%.2f %.2f %s %.2f %.2f %s\n",
	  item->kind.rect.x,
	  yflip - item->kind.rect.y - (item->kind.rect.h - 1.0),
	  psc[PSmoveto].command,
	  item->kind.rect.w - 1.0, item->kind.rect.h - 1.0,
	  psc[PSbox].command);
	break;
      case SciPlotFRect:
	fprintf(fd, "%.2f %.2f %s %.2f %.2f %s\n",
	  item->kind.rect.x,
	  yflip - item->kind.rect.y - (item->kind.rect.h - 1.0),
	  psc[PSmoveto].command,
	  item->kind.rect.w - 1.0, item->kind.rect.h - 1.0,
	  psc[PSfbox].command);
	break;
      case SciPlotPoly:
	fprintf(fd, "%.2f %.2f %s ",
	  item->kind.poly.x[0], yflip - item->kind.poly.y[0],
	  psc[PSmoveto].command);
	for (i = 1; i < item->kind.poly.count; i++) {
	  fprintf(fd, "%.2f %.2f %s ",
	    item->kind.poly.x[i],
	    yflip - item->kind.poly.y[i],
	    psc[PSpolyline].command);
	}
	fprintf(fd, "%s\n", psc[PSendpoly].command);
	break;
      case SciPlotFPoly:
	fprintf(fd, "%.2f %.2f %s ",
	  item->kind.poly.x[0], yflip - item->kind.poly.y[0],
	  psc[PSmoveto].command);
	for (i = 1; i < item->kind.poly.count; i++) {
	  fprintf(fd, "%.2f %.2f %s ",
	    item->kind.poly.x[i],
	    yflip - item->kind.poly.y[i],
	    psc[PSpolyline].command);
	}
	fprintf(fd, "%s\n", psc[PSendfill].command);
	break;
      case SciPlotCircle:
	fprintf(fd, "%.2f %.2f %.2f %s\n",
	  item->kind.circ.x, yflip - item->kind.circ.y,
	  item->kind.circ.r,
	  psc[PScircle].command);
	break;
      case SciPlotFCircle:
	fprintf(fd, "%.2f %.2f %.2f %s\n",
	  item->kind.circ.x, yflip - item->kind.circ.y,
	  item->kind.circ.r,
	  psc[PSfcircle].command);
	break;
      case SciPlotText:
	fprintf(fd, "font-%d %.2f %.2f %s (%s) show\n",
	  item->kind.text.font,
	  item->kind.text.x, yflip - item->kind.text.y,
	  psc[PSmoveto].command,
	  item->kind.text.text);
	break;
      case SciPlotVText:
	fprintf(fd, "font-%d %.2f %.2f %s (%s) show %s\n",
	  item->kind.text.font,
	  item->kind.text.x, yflip - item->kind.text.y,
	  psc[PSvmoveto].command,
	  item->kind.text.text,
	  psc[PSnormal].command);
	break;
      case SciPlotClipRegion:
	fprintf(fd, "%.2f %.2f %s %.2f %.2f %s\n",
	  item->kind.line.x1,
	  yflip - item->kind.line.y1 - item->kind.line.y2,
	  psc[PSmoveto].command,
	  item->kind.line.x2, item->kind.line.y2,
	  psc[PSclipbox].command);
	break;
      case SciPlotClipClear:
	fprintf(fd, "%s\n", psc[PSunclip].command);
	break;
      default:
	break;
      }
    }
    loopcount++;
    item++;
  }
}

Boolean 
SciPlotPSCreateFancy (SciPlotWidget w, char *filename, int drawborder, char *titles, Boolean usecolor)
{
  FILE *fd;
  float scale, xoff, yoff, xmax, ymax, yflip, aspect, border, titlefontsize;
  int i;
  PScommands *p;
  char fontname[128];

  if (!(fd = fopen(filename, "w"))) {
    XtWarning("SciPlotPSCreate: Unable to open postscript file.");
    return False;
  }
  DrawAll(w);

  aspect = (float) w->core.width / (float) w->core.height;
  border = 36.0;
  if (aspect > (612.0 / 792.0)) {
    scale = (612.0 - (2 * border)) / (float) w->core.width;
    xoff = border;
    yoff = (792.0 - (2 * border) - scale * (float) w->core.height) / 2.0;
    xmax = xoff + scale * (float) w->core.width;
    ymax = yoff + scale * (float) w->core.height;
  }
  else {
    scale = (792.0 - (2 * border)) / (float) w->core.height;
    yoff = border;
    xoff = (612.0 - (2 * border) - scale * (float) w->core.width) / 2.0;
    xmax = xoff + scale * (float) w->core.width;
    ymax = yoff + scale * (float) w->core.height;
  }
  yflip = w->core.height;
  fprintf(fd, "%s\n%s %.2f  %s\n%s %f %f %f %f\n%s\n",
    "%!PS-ADOBE-3.0 EPSF-3.0",
    "%%Creator: SciPlot Widget",
    _SCIPLOT_WIDGET_VERSION,
    "Copyright (c) 1995 Robert W. McMullen",
    "%%BoundingBox:", xoff, yoff, xmax, ymax,
    "%%EndComments");

  p = psc;
  while (p->command) {
    fprintf(fd, "/%s {%s} bind def\n", p->command, p->prolog);
    p++;
  }

  for (i = 0; i < w->plot.num_fonts; i++) {
    FontnumPostScriptString(w, i, fontname);
    fprintf(fd, "/font-%d {%s setfont} bind def\n",
      i, fontname);
  }
  titlefontsize = 10.0;
  fprintf(fd, "/font-title {/%s findfont %f scalefont setfont} bind def\n",
    "Times-Roman", titlefontsize);
  fprintf(fd, "%f setlinewidth\n", 0.001);
  fprintf(fd, "newpath gsave\n%f %f translate %f %f scale\n",
    xoff, yoff, scale, scale);

  ItemPSDrawAll(w, fd, yflip, usecolor);

  fprintf(fd, "grestore\n");

  if (drawborder) {
    fprintf(fd, "%.2f %.2f %s %.2f %.2f %s\n",
      border, border,
      psc[PSmoveto].command,
      612.0 - 2.0 * border, 792.0 - 2.0 * border,
      psc[PSbox].command);
  }
  if (titles) {
    char *ptr;
    char buf[256];
    int len, i, j;
    float x, y;

    x = border + titlefontsize;
    y = 792.0 - border - (2.0 * titlefontsize);
    len = strlen(titles);
    ptr = titles;
    i = 0;
    while (i < len) {
      j = 0;
      while ((*ptr != '\n') && (i < len)) {
	if ((*ptr == '(') || (*ptr == ')'))
	  buf[j++] = '\\';
	buf[j++] = *ptr;
	ptr++;
	i++;
      }
      buf[j] = '\0';
      ptr++;
      i++;
      fprintf(fd, "font-title %.2f %.2f %s (%s) show\n",
	x, y, psc[PSmoveto].command, buf);
      y -= titlefontsize * 1.5;
    }
    if (border) {
      y += titlefontsize * 0.5;
      fprintf(fd, "%.2f %.2f %s %.2f %.2f %s\n",
	border, y,
	psc[PSmoveto].command,
	612.0 - border, y,
	psc[PSlineto].command);
    }
  }

  fprintf(fd, "showpage\n");
  fclose(fd);
  return True;
}

Boolean 
SciPlotPSCreate (Widget wi, char *filename)
{
  SciPlotWidget w;

  if (!XtIsSciPlot(wi)) {
    XtWarning("SciPlotPSCreate: Not a SciPlot widget.");
    return False;
  }

  w = (SciPlotWidget) wi;
  return SciPlotPSCreateFancy(w, filename, False, NULL, False);
}

Boolean 
SciPlotPSCreateColor (Widget wi, char *filename)
{
  SciPlotWidget w;

  if (!XtIsSciPlot(wi)) {
    XtWarning("SciPlotPSCreate: Not a SciPlot widget.");
    return False;
  }

  w = (SciPlotWidget) wi;
  return SciPlotPSCreateFancy(w, filename, False, NULL, True);
}


/*
 * Private device independent drawing functions
 */

static void 
EraseClassItems (SciPlotWidget w, SciPlotDrawingEnum drawing)
{
  SciPlotItem *item;
  int i;

  if (!XtIsRealized((Widget) w))
    return;
  item = w->plot.drawlist;
  i = 0;
  while (i < w->plot.num_drawlist) {
    if (item->drawing_class == drawing) {
      item->kind.any.color = 0;
      item->kind.any.style = XtLINE_SOLID;
      ItemDraw(w, item);
    }
    i++;
    item++;
  }
}

static void 
EraseAllItems (SciPlotWidget w)
{
  SciPlotItem *item;
  int i;

  item = w->plot.drawlist;
  i = 0;
  while (i < w->plot.num_drawlist) {
    if ((item->type > SciPlotStartTextTypes) &&
      (item->type < SciPlotEndTextTypes))
      XtFree(item->kind.text.text);
    i++;
    item++;
  }
  w->plot.num_drawlist = 0;
}

static void 
EraseAll (SciPlotWidget w)
{
  EraseAllItems(w);
  if (XtIsRealized((Widget) w))
    XClearWindow(XtDisplay(w), XtWindow(w));
}

static SciPlotItem *
ItemGetNew (SciPlotWidget w)
{
  SciPlotItem *item;

  w->plot.num_drawlist++;
  if (w->plot.num_drawlist >= w->plot.alloc_drawlist) {
    w->plot.alloc_drawlist += NUMPLOTITEMEXTRA;
    w->plot.drawlist = (SciPlotItem *) XtRealloc((char *) w->plot.drawlist,
      w->plot.alloc_drawlist * sizeof(SciPlotItem));
    if (!w->plot.drawlist) {
      printf("Can't realloc memory for SciPlotItem list\n");
      exit(1);
    }
#ifdef DEBUG_SCIPLOT
    printf("Alloced #%d for drawlist\n", w->plot.alloc_drawlist);
#endif
  }
  item = w->plot.drawlist + (w->plot.num_drawlist - 1);
  item->type = SciPlotFALSE;
  item->drawing_class = w->plot.current_id;
  return item;
}


static void
LineSet(SciPlotWidget w, real x1, real y1, real x2, real y2,
  int color, int style)
{
  SciPlotItem *item;

  item = ItemGetNew(w);
  item->kind.any.color = (short) color;
  item->kind.any.style = (short) style;
  item->kind.line.x1 = (real) x1;
  item->kind.line.y1 = (real) y1;
  item->kind.line.x2 = (real) x2;
  item->kind.line.y2 = (real) y2;
  item->type = SciPlotLine;
  ItemDraw(w, item);
}

static void
RectSet(SciPlotWidget w, real x1, real y1, real x2, real y2,
  int color, int style)
{
  SciPlotItem *item;
  real x, y, width, height;

  if (x1 < x2)
    x = x1, width = (x2 - x1 + 1);
  else
    x = x2, width = (x1 - x2 + 1);
  if (y1 < y2)
    y = y1, height = (y2 - y1 + 1);
  else
    y = y2, height = (y1 - y2 + 1);

  item = ItemGetNew(w);
  item->kind.any.color = (short) color;
  item->kind.any.style = (short) style;
  item->kind.rect.x = (real) x;
  item->kind.rect.y = (real) y;
  item->kind.rect.w = (real) width;
  item->kind.rect.h = (real) height;
  item->type = SciPlotRect;
  ItemDraw(w, item);
}

static void 
FilledRectSet (SciPlotWidget w, real x1, real y1, real x2, real y2, int color, int style)
{
  SciPlotItem *item;
  real x, y, width, height;

  if (x1 < x2)
    x = x1, width = (x2 - x1 + 1);
  else
    x = x2, width = (x1 - x2 + 1);
  if (y1 < y2)
    y = y1, height = (y2 - y1 + 1);
  else
    y = y2, height = (y1 - y2 + 1);

  item = ItemGetNew(w);
  item->kind.any.color = (short) color;
  item->kind.any.style = (short) style;
  item->kind.rect.x = (real) x;
  item->kind.rect.y = (real) y;
  item->kind.rect.w = (real) width;
  item->kind.rect.h = (real) height;
  item->type = SciPlotFRect;
  ItemDraw(w, item);
}

static void 
TriSet (SciPlotWidget w, real x1, real y1, real x2, real y2, real x3, real y3, int color, int style)
{
  SciPlotItem *item;

  item = ItemGetNew(w);
  item->kind.any.color = (short) color;
  item->kind.any.style = (short) style;
  item->kind.poly.count = 3;
  item->kind.poly.x[0] = (real) x1;
  item->kind.poly.y[0] = (real) y1;
  item->kind.poly.x[1] = (real) x2;
  item->kind.poly.y[1] = (real) y2;
  item->kind.poly.x[2] = (real) x3;
  item->kind.poly.y[2] = (real) y3;
  item->type = SciPlotPoly;
  ItemDraw(w, item);
}

static void 
FilledTriSet (SciPlotWidget w, real x1, real y1, real x2, real y2, real x3, real y3, int color, int style)
{
  SciPlotItem *item;

  item = ItemGetNew(w);
  item->kind.any.color = (short) color;
  item->kind.any.style = (short) style;
  item->kind.poly.count = 3;
  item->kind.poly.x[0] = (real) x1;
  item->kind.poly.y[0] = (real) y1;
  item->kind.poly.x[1] = (real) x2;
  item->kind.poly.y[1] = (real) y2;
  item->kind.poly.x[2] = (real) x3;
  item->kind.poly.y[2] = (real) y3;
  item->type = SciPlotFPoly;
  ItemDraw(w, item);
}

static void 
QuadSet (SciPlotWidget w, real x1, real y1, real x2, real y2, real x3, real y3, real x4, real y4, int color, int style)
{
  SciPlotItem *item;

  item = ItemGetNew(w);
  item->kind.any.color = (short) color;
  item->kind.any.style = (short) style;
  item->kind.poly.count = 4;
  item->kind.poly.x[0] = (real) x1;
  item->kind.poly.y[0] = (real) y1;
  item->kind.poly.x[1] = (real) x2;
  item->kind.poly.y[1] = (real) y2;
  item->kind.poly.x[2] = (real) x3;
  item->kind.poly.y[2] = (real) y3;
  item->kind.poly.x[3] = (real) x4;
  item->kind.poly.y[3] = (real) y4;
  item->type = SciPlotPoly;
  ItemDraw(w, item);
}

static void 
FilledQuadSet (SciPlotWidget w, real x1, real y1, real x2, real y2, real x3, real y3, real x4, real y4, int color, int style)
{
  SciPlotItem *item;

  item = ItemGetNew(w);
  item->kind.any.color = (short) color;
  item->kind.any.style = (short) style;
  item->kind.poly.count = 4;
  item->kind.poly.x[0] = (real) x1;
  item->kind.poly.y[0] = (real) y1;
  item->kind.poly.x[1] = (real) x2;
  item->kind.poly.y[1] = (real) y2;
  item->kind.poly.x[2] = (real) x3;
  item->kind.poly.y[2] = (real) y3;
  item->kind.poly.x[3] = (real) x4;
  item->kind.poly.y[3] = (real) y4;
  item->type = SciPlotFPoly;
  ItemDraw(w, item);
}

static void 
CircleSet (SciPlotWidget w, real x, real y, real r, int color, int style)
{
  SciPlotItem *item;

  item = ItemGetNew(w);
  item->kind.any.color = (short) color;
  item->kind.any.style = (short) style;
  item->kind.circ.x = (real) x;
  item->kind.circ.y = (real) y;
  item->kind.circ.r = (real) r;
  item->type = SciPlotCircle;
  ItemDraw(w, item);
}

static void 
FilledCircleSet (SciPlotWidget w, real x, real y, real r, int color, int style)
{
  SciPlotItem *item;

  item = ItemGetNew(w);
  item->kind.any.color = (short) color;
  item->kind.any.style = (short) style;
  item->kind.circ.x = (real) x;
  item->kind.circ.y = (real) y;
  item->kind.circ.r = (real) r;
  item->type = SciPlotFCircle;
  ItemDraw(w, item);
}

static void 
TextSet (SciPlotWidget w, real x, real y, char *text, int color, int font)
{
  SciPlotItem *item;

  item = ItemGetNew(w);
  item->kind.any.color = (short) color;
  item->kind.any.style = 0;
  item->kind.text.x = (real) x;
  item->kind.text.y = (real) y;
  item->kind.text.length = strlen(text);
  item->kind.text.text = XtMalloc((int) item->kind.text.length + 1);
  item->kind.text.font = font;
  strcpy(item->kind.text.text, text);
  item->type = SciPlotText;
  ItemDraw(w, item);
#ifdef DEBUG_SCIPLOT_TEXT
  if (1) {
    real x1, y1;

    y -= FontnumAscent(w, font);
    y1 = y + FontnumHeight(w, font) - 1.0;
    x1 = x + FontnumTextWidth(w, font, text) - 1.0;
    RectSet(w, x, y, x1, y1, color, XtLINE_SOLID);
  }
#endif
}

static void 
TextCenter (SciPlotWidget w, real x, real y, char *text, int color, int font)
{
  x -= FontnumTextWidth(w, font, text) / 2.0;
  y += FontnumHeight(w, font) / 2.0 - FontnumDescent(w, font);
  TextSet(w, x, y, text, color, font);
}

static void 
VTextSet (SciPlotWidget w, real x, real y, char *text, int color, int font)
{
  SciPlotItem *item;

  item = ItemGetNew(w);
  item->kind.any.color = (short) color;
  item->kind.any.style = 0;
  item->kind.text.x = (real) x;
  item->kind.text.y = (real) y;
  item->kind.text.length = strlen(text);
  item->kind.text.text = XtMalloc((int) item->kind.text.length + 1);
  item->kind.text.font = font;
  strcpy(item->kind.text.text, text);
  item->type = SciPlotVText;
  ItemDraw(w, item);
#ifdef DEBUG_SCIPLOT_TEXT
  if (1) {
    real x1, y1;

    x += FontnumDescent(w, font);
    x1 = x - FontnumHeight(w, font) - 1.0;
    y1 = y - FontnumTextWidth(w, font, text) - 1.0;
    RectSet(w, x, y, x1, y1, color, XtLINE_SOLID);
  }
#endif
}

static void 
VTextCenter (SciPlotWidget w, real x, real y, char *text, int color, int font)
{
  x += FontnumHeight(w, font) / 2.0 - FontnumDescent(w, font);
  y += FontnumTextWidth(w, font, text) / 2.0;
  VTextSet(w, x, y, text, color, font);
}

static void 
ClipSet (SciPlotWidget w)
{
  SciPlotItem *item;

  if (w->plot.ChartType == XtCARTESIAN) {
    item = ItemGetNew(w);
    item->kind.any.style = XtLINE_SOLID;
    item->kind.any.color = 1;
    item->kind.line.x1 = w->plot.x.Origin;
    item->kind.line.x2 = w->plot.x.Size;
    item->kind.line.y1 = w->plot.y.Origin;
    item->kind.line.y2 = w->plot.y.Size;
#ifdef DEBUG_SCIPLOT
    printf("clipping region: x=%f y=%f w=%f h=%f\n",
      item->kind.line.x1,
      item->kind.line.y1,
      item->kind.line.x2,
      item->kind.line.y2
      );
#endif
    item->type = SciPlotClipRegion;
    ItemDraw(w, item);
  }
}

static void 
ClipClear (SciPlotWidget w)
{
  SciPlotItem *item;

  if (w->plot.ChartType == XtCARTESIAN) {
    item = ItemGetNew(w);
    item->kind.any.style = XtLINE_SOLID;
    item->kind.any.color = 1;
    item->type = SciPlotClipClear;
    ItemDraw(w, item);
  }
}


/*
 * Private data point to screen location converters
 */

static real 
PlotX (SciPlotWidget w, real xin)
{
  real xout;

  if (w->plot.XLog)
    xout = w->plot.x.Origin +
      ((log10(xin) - log10(w->plot.x.DrawOrigin)) *
      (w->plot.x.Size / w->plot.x.DrawSize));
  else
    xout = w->plot.x.Origin +
      ((xin - w->plot.x.DrawOrigin) *
      (w->plot.x.Size / w->plot.x.DrawSize));
  return xout;
}

static real 
PlotY (SciPlotWidget w, real yin)
{
  real yout;

  if (w->plot.YLog)
    yout = w->plot.y.Origin + w->plot.y.Size -
      ((log10(yin) - log10(w->plot.y.DrawOrigin)) *
      (w->plot.y.Size / w->plot.y.DrawSize));
  else
    yout = w->plot.y.Origin + w->plot.y.Size -
      ((yin - w->plot.y.DrawOrigin) *
      (w->plot.y.Size / w->plot.y.DrawSize));
  return yout;
}

static void 
PlotRTRadians (SciPlotWidget w, real r, real t, real *xout, real *yout)
{
  *xout = w->plot.x.Center + (r * (real) cos(t) /
    w->plot.PolarScale * w->plot.x.Size / 2.0);
  *yout = w->plot.y.Center + (-r * (real) sin(t) /
    w->plot.PolarScale * w->plot.x.Size / 2.0);
}

static void 
PlotRTDegrees (SciPlotWidget w, real r, real t, real *xout, real *yout)
{
  t *= DEG2RAD;
  PlotRTRadians(w, r, t, xout, yout);
}

static void 
PlotRT (SciPlotWidget w, real r, real t, real *xout, real *yout)
{
  if (w->plot.Degrees)
    t *= DEG2RAD;
  PlotRTRadians(w, r, t, xout, yout);
}


/*
 * Private calculation utilities for axes
 */

#define NUMBER_MINOR	8
#define MAX_MAJOR	8
static float CAdeltas[8] =
{0.1, 0.2, 0.25, 0.5, 1.0, 2.0, 2.5, 5.0};
static int CAdecimals[8] =
{0, 0, 1, 0, 0, 0, 1, 0};
static int CAminors[8] =
{4, 4, 4, 5, 4, 4, 4, 5};

static void 
ComputeAxis (SciPlotAxis *axis, real min, real max, Boolean log)
{
  real range, rnorm, delta, calcmin, calcmax;
  int nexp, majornum, minornum, majordecimals, decimals, i;

  range = max - min;
  if (log) {
    if (range==0.0) {
      calcmin = powi(10.0, (int) floor(log10(min)));
      calcmax = 10.0*calcmin;
    }
    else {
      calcmin = powi(10.0, (int) floor(log10(min)));
      calcmax = powi(10.0, (int) ceil(log10(max)));
    }
    
/*     printf("calcmin=%e min=%e   calcmax=%e max=%e\n",calcmin,min, */
/*       calcmax,max); */
    
    delta = 10.0;

    axis->DrawOrigin = calcmin;
    axis->DrawMax = calcmax;
    axis->DrawSize = log10(calcmax) - log10(calcmin);
    axis->MajorInc = delta;
    axis->MajorNum = (int) (log10(calcmax) - log10(calcmin)) + 1;
    axis->MinorNum = 10;
    axis->Precision = -(int) (log10(calcmin) * 1.0001);
#ifdef DEBUG_SCIPLOT
    printf("calcmin=%e log=%e (int)log=%d  Precision=%d\n",
      calcmin, log10(calcmin), (int) (log10(calcmin) * 1.0001), axis->Precision);
#endif
    if (axis->Precision < 0)
      axis->Precision = 0;
  }
  else {
    if (range==0.0) nexp=0;
    else nexp = (int) floor(log10(range));
    rnorm = range / powi(10.0, nexp);
    for (i = 0; i < NUMBER_MINOR; i++) {
      delta = CAdeltas[i];
      minornum = CAminors[i];
      majornum = (int) ((rnorm + 0.9999 * delta) / delta);
      majordecimals = CAdecimals[i];
      if (majornum <= MAX_MAJOR)
	break;
    }
    delta *= powi(10.0, nexp);
#ifdef DEBUG_SCIPLOT
    printf("nexp=%d range=%f rnorm=%f delta=%f\n", nexp, range, rnorm, delta);
#endif

    if (min < 0.0)
      calcmin = ((float) ((int) ((min - .9999 * delta) / delta))) * delta;
    else if ((min > 0.0) && (min < 1.0))
      calcmin = ((float) ((int) ((1.0001 * min) / delta))) * delta;
    else if (min >= 1.0)
      calcmin = ((float) ((int) ((.9999 * min) / delta))) * delta;
    else
      calcmin = min;
    if (max < 0.0)
      calcmax = ((float) ((int) ((.9999 * max) / delta))) * delta;
    else if (max > 0.0)
      calcmax = ((float) ((int) ((max + .9999 * delta) / delta))) * delta;
    else
      calcmax = max;

    axis->DrawOrigin = calcmin;
    axis->DrawMax = calcmax;
    axis->DrawSize = calcmax - calcmin;
    axis->MajorInc = delta;
    axis->MajorNum = majornum;
    axis->MinorNum = minornum;

    delta = log10(axis->MajorInc);
    if (delta > 0.0)
      decimals = -(int) floor(delta) + majordecimals;
    else
      decimals = (int) ceil(-delta) + majordecimals;
    if (decimals < 0)
      decimals = 0;
#ifdef DEBUG_SCIPLOT
    printf("delta=%f majordecimals=%d decimals=%d\n",
      delta, majordecimals, decimals);
#endif
    axis->Precision = decimals;
  }

#ifdef DEBUG_SCIPLOT
  printf("Tics: min=%f max=%f size=%f  major inc=%f #major=%d #minor=%d decimals=%d\n",
    axis->DrawOrigin, axis->DrawMax, axis->DrawSize,
    axis->MajorInc, axis->MajorNum, axis->MinorNum, axis->Precision);
#endif
}

static void 
ComputeDrawingRange (SciPlotWidget w)
{
  if (w->plot.ChartType == XtCARTESIAN) {
    ComputeAxis(&w->plot.x, w->plot.Min.x, w->plot.Max.x,
      w->plot.XLog);
    ComputeAxis(&w->plot.y, w->plot.Min.y, w->plot.Max.y,
      w->plot.YLog);
  }
  else {
    ComputeAxis(&w->plot.x, (real) 0.0, w->plot.Max.x,
      (Boolean) FALSE);
    w->plot.PolarScale = w->plot.x.DrawMax;
  }
}

static Boolean 
CheckMinMax (SciPlotWidget w)
{
  register int i, j;
  register SciPlotList *p;
  register real val;

  if (w->plot.ChartType == XtCARTESIAN) {
    for (i = 0; i < w->plot.num_plotlist; i++) {
      p = w->plot.plotlist + i;
      if (p->draw) {
	for (j = 0; j < p->number; j++) {
          
            /* Don't count the "break in line segment" flag for Min/Max */
          if (p->data[j].x > SCIPLOT_SKIP_VAL &&
              p->data[j].y > SCIPLOT_SKIP_VAL) {
            
            val = p->data[j].x;
            if (val > w->plot.x.DrawMax || val < w->plot.x.DrawOrigin)
              return True;
            val = p->data[j].y;
            if (val > w->plot.y.DrawMax || val < w->plot.y.DrawOrigin)
              return True;
          }
        }
      }
    }
  }
  else {
    for (i = 0; i < w->plot.num_plotlist; i++) {
      p = w->plot.plotlist + i;
      if (p->draw) {
	for (j = 0; j < p->number; j++) {
	  val = p->data[j].x;
	  if (val > w->plot.Max.x || val < w->plot.Min.x)
	    return True;
	}
      }
    }
  }
  return False;
}

static void 
ComputeMinMax (SciPlotWidget w)
{
  register int i, j;
  register SciPlotList *p;
  register real val;
  Boolean firstx, firsty;

  w->plot.Min.x = w->plot.Min.y = w->plot.Max.x = w->plot.Max.y = 1.0;
  firstx = True;
  firsty = True;

  for (i = 0; i < w->plot.num_plotlist; i++) {
    p = w->plot.plotlist + i;
    if (p->draw) {
      for (j = 0; j < p->number; j++) {
          
          /* Don't count the "break in line segment" flag for Min/Max */
        if (p->data[j].x > SCIPLOT_SKIP_VAL &&
            p->data[j].y > SCIPLOT_SKIP_VAL) {
            
          val = p->data[j].x;
          if (!w->plot.XLog || (w->plot.XLog && (val > 0.0))) {
            if (firstx) {
              w->plot.Min.x = w->plot.Max.x = val;
              firstx = False;
            }
            else {
              if (val > w->plot.Max.x)
                w->plot.Max.x = val;
              else if (val < w->plot.Min.x)
                w->plot.Min.x = val;
            }
          }

          val = p->data[j].y;
          if (!w->plot.YLog || (w->plot.YLog && (val > 0.0))) {
            if (firsty) {
              w->plot.Min.y = w->plot.Max.y = val;
              firsty = False;
            }
            else {
              if (val > w->plot.Max.y)
                w->plot.Max.y = val;
              else if (val < w->plot.Min.y)
                w->plot.Min.y = val;
            }
          }
        }
        
      }
    }
  }

    /* fix defaults if there is only one point. */
  if (firstx) {
    if (w->plot.XLog) {
      w->plot.Min.x = 1.0;
      w->plot.Max.x = 10.0;
    }
    else {
      w->plot.Min.x = 0.0;
      w->plot.Max.x = 10.0;
    }
  }
  if (firsty) {
    if (w->plot.YLog) {
      w->plot.Min.y = 1.0;
      w->plot.Max.y = 10.0;
    }
    else {
      w->plot.Min.y = 0.0;
      w->plot.Max.y = 10.0;
    }
  }
  if (w->plot.ChartType == XtCARTESIAN) {
    if (!w->plot.XLog) {
      if (!w->plot.XAutoScale) {
	w->plot.Min.x = w->plot.UserMin.x;
	w->plot.Max.x = w->plot.UserMax.x;
      }
      else if (w->plot.XOrigin) {
	if (w->plot.Min.x > 0.0)
	  w->plot.Min.x = 0.0;
	if (w->plot.Max.x < 0.0)
	  w->plot.Max.x = 0.0;
      }
      if (fabs(w->plot.Min.x - w->plot.Max.x) < 1.e-10) {
	w->plot.Min.x -= .5;
	w->plot.Max.x += .5;
      }
    }
    if (!w->plot.YLog) {
      if (!w->plot.YAutoScale) {
	w->plot.Min.y = w->plot.UserMin.y;
	w->plot.Max.y = w->plot.UserMax.y;
      }
      else if (w->plot.YOrigin) {
	if (w->plot.Min.y > 0.0)
	  w->plot.Min.y = 0.0;
	if (w->plot.Max.y < 0.0)
	  w->plot.Max.y = 0.0;
      }
      if (fabs(w->plot.Min.y - w->plot.Max.y) < 1.e-10) {
	w->plot.Min.y -= .5;
	w->plot.Max.y += .5;
      }
    }
  }
  else {
    if (fabs(w->plot.Min.x) > fabs(w->plot.Max.x))
      w->plot.Max.x = fabs(w->plot.Min.x);
  }

#ifdef DEBUG_SCIPLOT
  printf("Min: (%f,%f)\tMax: (%f,%f)\n",
    w->plot.Min.x, w->plot.Min.y,
    w->plot.Max.x, w->plot.Max.y);
#endif
}

static void 
ComputeLegendDimensions (SciPlotWidget w)
{
  real current, xmax, ymax;
  int i;
  SciPlotList *p;

  if (w->plot.ShowLegend) {
    xmax = 0.0;
    ymax = 2.0 * (real) w->plot.LegendMargin;

    for (i = 0; i < w->plot.num_plotlist; i++) {
      p = w->plot.plotlist + i;
      if (p->draw) {
	current = (real) w->plot.Margin +
	  (real) w->plot.LegendMargin * 3.0 +
	  (real) w->plot.LegendLineSize +
	  FontnumTextWidth(w, w->plot.axisFont, p->legend);
	if (current > xmax)
	  xmax = current;
	ymax += FontnumHeight(w, w->plot.axisFont);
      }
    }

    w->plot.x.LegendSize = xmax;
    w->plot.x.LegendPos = (real) w->plot.Margin;
    w->plot.y.LegendSize = ymax;
    w->plot.y.LegendPos = 0.0;
  }
  else {
    w->plot.x.LegendSize =
      w->plot.x.LegendPos =
      w->plot.y.LegendSize =
      w->plot.y.LegendPos = 0.0;
  }
}

static void 
ComputeDimensions (SciPlotWidget w)
{
  real x, y, width, height, axisnumbersize, axisXlabelsize, axisYlabelsize;

/* x,y is the origin of the upper left corner of the drawing area inside
 * the widget.  Doesn't necessarily have to be (Margin,Margin) as it is now.
 */
  x = (real) w->plot.Margin;
  y = (real) w->plot.Margin;

/* width = (real)w->core.width - (real)w->plot.Margin - x -
 * **           legendwidth - AxisFontHeight
 */
  width = (real) w->core.width - (real) w->plot.Margin - x -
    w->plot.x.LegendSize;

/* height = (real)w->core.height - (real)w->plot.Margin - y
 *           - Height of axis numbers (including margin)
 *           - Height of axis label (including margin)
 *           - Height of Title (including margin)
 */
  height = (real) w->core.height - (real) w->plot.Margin - y;

  w->plot.x.Origin = x;
  w->plot.y.Origin = y;

/* Adjust the size depending upon what sorts of text are visible. */
  if (w->plot.ShowTitle)
    height -= (real) w->plot.TitleMargin +
      FontnumHeight(w, w->plot.titleFont);

  if (w->plot.ChartType == XtCARTESIAN) {
    axisnumbersize = (real) w->plot.Margin +
      FontnumHeight(w, w->plot.axisFont);
    if (w->plot.XAxisNumbers) {
      height -= axisnumbersize;
    }
    if (w->plot.YAxisNumbers) {
      width -= axisnumbersize;
      w->plot.x.Origin += axisnumbersize;
    }
    
    if (w->plot.ShowXLabel) {
      axisXlabelsize = (real) w->plot.Margin +
	FontnumHeight(w, w->plot.labelFont);
      height -= axisXlabelsize;
    }
    if (w->plot.ShowYLabel) {
      axisYlabelsize = (real) w->plot.Margin +
	FontnumHeight(w, w->plot.labelFont);
      width -= axisYlabelsize;
      w->plot.x.Origin += axisYlabelsize;
    }
  }

  w->plot.x.Size = width;
  w->plot.y.Size = height;

/* Adjust parameters for polar plot */
  if (w->plot.ChartType == XtPOLAR) {
    if (height < width)
      w->plot.x.Size = height;
  }
  w->plot.x.Center = w->plot.x.Origin + (width / 2.0);
  w->plot.y.Center = w->plot.y.Origin + (height / 2.0);

}

static void 
AdjustDimensionsCartesian (SciPlotWidget w)
{
  real xextra, yextra, val, xhorz;
  real x, y, width, height, axisnumbersize, axisXlabelsize, axisYlabelsize;
  char numberformat[16], label[16];
  int precision;

/* Compute xextra and yextra, which are the extra distances that the text
 * labels on the axes stick outside of the graph.
 */
  xextra = yextra = 0.0;
  if (w->plot.XAxisNumbers) {
    precision = w->plot.x.Precision;
    if (w->plot.XLog) {
      val = w->plot.x.DrawMax;
      precision -= w->plot.x.MajorNum;
      if (precision < 0)
        precision = 0;
    }
    else
      val = w->plot.x.DrawOrigin + floor(w->plot.x.DrawSize /
        w->plot.x.MajorInc) * w->plot.x.MajorInc;
    x = PlotX(w, val);
    sprintf(numberformat, "%%.%df", precision);
    sprintf(label, numberformat, val);
    x += FontnumTextWidth(w, w->plot.axisFont, label);
    if ((int) x > w->core.width) {
      xextra = ceil(x - w->core.width + w->plot.Margin);
      if (xextra < 0.0)
        xextra = 0.0;
    }
  }
  
  yextra=xhorz=0.0;
  if (w->plot.YAxisNumbers) {
    precision = w->plot.y.Precision;
    if (w->plot.YLog) {
      int p1,p2;

      p1=precision;
      val = w->plot.y.DrawOrigin;
      if (p1 > 0)
        p1--;
    
      val = w->plot.y.DrawMax;
      p2 = precision - w->plot.y.MajorNum;
      if (p2 < 0)
        p2 = 0;

      if (p1>p2) precision=p1;
      else precision=p2;
    }
    else
      val = w->plot.y.DrawOrigin + floor(w->plot.y.DrawSize /
        w->plot.y.MajorInc * 1.0001) * w->plot.y.MajorInc;
    y = PlotY(w, val);
    sprintf(numberformat, "%%.%df", precision);
    sprintf(label, numberformat, val);
#ifdef DEBUG_SCIPLOT
    printf("ylabel=%s\n", label);
#endif
    if (w->plot.YNumHorz) {
      yextra=FontnumHeight(w, w->plot.axisFont)/2.0;
      xhorz=FontnumTextWidth(w, w->plot.axisFont, label) + (real)w->plot.Margin;
    }
    else {
      y -= FontnumTextWidth(w, w->plot.axisFont, label);
      if ((int) y <= 0) {
        yextra = ceil(w->plot.Margin - y);
        if (yextra < 0.0)
          yextra = 0.0;
      }
    }
  }
  
/* x,y is the origin of the upper left corner of the drawing area inside
 * the widget.  Doesn't necessarily have to be (Margin,Margin) as it is now.
 */
  x = (real) w->plot.Margin + xhorz;
  y = (real) w->plot.Margin + yextra;

/* width = (real)w->core.width - (real)w->plot.Margin - x -
 *          legendwidth - AxisFontHeight
 */
  width = (real) w->core.width - (real) w->plot.Margin - x - xextra;


/* height = (real)w->core.height - (real)w->plot.Margin - y
 *           - Height of axis numbers (including margin)
 *           - Height of axis label (including margin)
 *           - Height of Title (including margin)
 */
  height = (real) w->core.height - (real) w->plot.Margin - y;

  w->plot.x.Origin = x;
  w->plot.y.Origin = y;

/* Adjust the size depending upon what sorts of text are visible. */
  if (w->plot.ShowTitle)
    height -= (real) w->plot.TitleMargin +
      FontnumHeight(w, w->plot.titleFont);

  axisXlabelsize = 0.0;
  axisYlabelsize = 0.0;
  axisnumbersize = (real) w->plot.Margin +
    FontnumHeight(w, w->plot.axisFont);
  if (w->plot.XAxisNumbers) {
    height -= axisnumbersize;
  }
  if (w->plot.YAxisNumbers && !w->plot.YNumHorz) {
    width -= axisnumbersize;
    w->plot.x.Origin += axisnumbersize;
  }
  
  if (w->plot.ShowXLabel) {
    axisXlabelsize = (real) w->plot.Margin +
      FontnumHeight(w, w->plot.labelFont);
    height -= axisXlabelsize;
  }
  if (w->plot.ShowYLabel) {
    axisYlabelsize = (real) w->plot.Margin +
      FontnumHeight(w, w->plot.labelFont);
    width -= axisYlabelsize;
    w->plot.x.Origin += axisYlabelsize;
  }

/* Move legend position to the right of the plot */
  if (w->plot.LegendThroughPlot) {
    w->plot.x.LegendPos += w->plot.x.Origin + width - w->plot.x.LegendSize;
    w->plot.y.LegendPos += w->plot.y.Origin;
  }
  else {
    width -= w->plot.x.LegendSize;
    w->plot.x.LegendPos += w->plot.x.Origin + width;
    w->plot.y.LegendPos += w->plot.y.Origin;
  }

  w->plot.x.Size = width;
  w->plot.y.Size = height;

  w->plot.y.AxisPos = w->plot.y.Origin + w->plot.y.Size +
    (real) w->plot.Margin +
    FontnumAscent(w, w->plot.axisFont);
  if (w->plot.YNumHorz) {
    w->plot.x.AxisPos = w->plot.x.Origin - (real) w->plot.Margin;
  }
  else {
    w->plot.x.AxisPos = w->plot.x.Origin -
      (real) w->plot.Margin -
      FontnumDescent(w, w->plot.axisFont);
  }
  
  w->plot.y.LabelPos = w->plot.y.Origin + w->plot.y.Size +
    (real) w->plot.Margin + (FontnumHeight(w, w->plot.labelFont) / 2.0);
  if (w->plot.XAxisNumbers)
    w->plot.y.LabelPos += axisnumbersize;
  if (w->plot.YAxisNumbers) {
    if (w->plot.YNumHorz) {
      w->plot.x.LabelPos = w->plot.x.Origin -
        xhorz - (real) w->plot.Margin -
        (FontnumHeight(w, w->plot.labelFont) / 2.0);
    }
    else {
      w->plot.x.LabelPos = w->plot.x.Origin -
        axisnumbersize - (real) w->plot.Margin -
        (FontnumHeight(w, w->plot.labelFont) / 2.0);
    }
  }
  else {
    w->plot.x.LabelPos = w->plot.x.Origin - (real) w->plot.Margin -
        (FontnumHeight(w, w->plot.labelFont) / 2.0);
  }
  
  w->plot.y.TitlePos = (real) w->core.height - (real) w->plot.Margin;
  w->plot.x.TitlePos = (real) w->plot.Margin;

#ifdef DEBUG_SCIPLOT
  printf("y.Origin:		%f\n", w->plot.y.Origin);
  printf("y.Size:			%f\n", w->plot.y.Size);
  printf("axisnumbersize:		%f\n", axisnumbersize);
  printf("y.axisLabelSize:	%f\n", axisYlabelsize);
  printf("y.TitleSize:		%f\n",
    (real) w->plot.TitleMargin + FontnumHeight(w, w->plot.titleFont));
  printf("y.Margin:		%f\n", (real) w->plot.Margin);
  printf("total-------------------%f\n", w->plot.y.Origin + w->plot.y.Size +
    axisnumbersize + axisYlabelsize + (real) w->plot.Margin +
    (real) w->plot.TitleMargin + FontnumHeight(w, w->plot.titleFont));
  printf("total should be---------%f\n", (real) w->core.height);
#endif
}

static void 
AdjustDimensionsPolar (SciPlotWidget w)
{
  real x, y, xextra, yextra, val;
  real width, height, size;
  char numberformat[16], label[16];

/* Compute xextra and yextra, which are the extra distances that the text
 * labels on the axes stick outside of the graph.
 */
  xextra = yextra = 0.0;
  val = w->plot.PolarScale;
  PlotRTDegrees(w, val, 0.0, &x, &y);
  sprintf(numberformat, "%%.%df", w->plot.x.Precision);
  sprintf(label, numberformat, val);
  x += FontnumTextWidth(w, w->plot.axisFont, label);
  if ((int) x > w->core.width) {
    xextra = x - w->core.width + w->plot.Margin;
    if (xextra < 0.0)
      xextra = 0.0;
  }
  yextra = 0.0;


/* x,y is the origin of the upper left corner of the drawing area inside
 * the widget.  Doesn't necessarily have to be (Margin,Margin) as it is now.
 */
  w->plot.x.Origin = (real) w->plot.Margin;
  w->plot.y.Origin = (real) w->plot.Margin;

/* width = (real)w->core.width - (real)w->plot.Margin - x -
 *          legendwidth - AxisFontHeight
 */
  width = (real) w->core.width - (real) w->plot.Margin - w->plot.x.Origin - xextra;

/* height = (real)w->core.height - (real)w->plot.Margin - y
 *           - Height of axis numbers (including margin)
 *           - Height of axis label (including margin)
 *           - Height of Title (including margin)
 */
  height = (real) w->core.height - (real) w->plot.Margin - w->plot.y.Origin - yextra;

/* Adjust the size depending upon what sorts of text are visible. */
  if (w->plot.ShowTitle)
    height -= (real) w->plot.TitleMargin +
      FontnumHeight(w, w->plot.titleFont);

/* Only need to carry one number for the size, (since it is a circle!) */
  if (height < width)
    size = height;
  else
    size = width;

/* Assign some preliminary values */
  w->plot.x.Center = w->plot.x.Origin + (width / 2.0);
  w->plot.y.Center = w->plot.y.Origin + (height / 2.0);
  w->plot.x.LegendPos += width - w->plot.x.LegendSize;
  w->plot.y.LegendPos += w->plot.y.Origin;

/*
 * Check and see if the legend can fit in the blank space in the upper right
 *
 * To fit, the legend must:
 *   1) be less than half the width/height of the plot
 *   2) hmmm.
 */
  if (!w->plot.LegendThroughPlot) {
    real radius = size / 2.0;
    real dist;

    x = w->plot.x.LegendPos - w->plot.x.Center;
    y = (w->plot.y.LegendPos + w->plot.y.LegendSize) - w->plot.y.Center;

    dist = sqrt(x * x + y * y);
/*       printf("rad=%f dist=%f: legend=(%f,%f) center=(%f,%f)\n", */
/*              radius,dist,w->plot.x.LegendPos,w->plot.y.LegendPos, */
/*              w->plot.x.Center,w->plot.y.Center); */

    /* It doesn't fit if this check is true.  Make the plot smaller */

    /* This is a first cut horrible algorithm.  My calculus is a bit
     * rusty tonight--can't seem to figure out how to maximize a circle
     * in a rectangle with a rectangular chunk out of it. */
    if (dist < radius) {
      width -= w->plot.x.LegendSize;
      height -= w->plot.y.LegendSize;

      /* readjust some parameters */
      w->plot.x.Center = w->plot.x.Origin + width / 2.0;
      w->plot.y.Center = w->plot.y.Origin + w->plot.y.LegendSize + height / 2.0;
      if (height < width)
	size = height;
      else
	size = width;
    }

  }


/* OK, customization is finished when we reach here. */
  w->plot.x.Size = w->plot.y.Size = size;

  w->plot.y.TitlePos = w->plot.y.Center + w->plot.y.Size / 2.0 +
    (real) w->plot.TitleMargin +
    FontnumAscent(w, w->plot.titleFont);
  w->plot.x.TitlePos = w->plot.x.Origin;
}

static void 
AdjustDimensions (SciPlotWidget w)
{
  if (w->plot.ChartType == XtCARTESIAN) {
    AdjustDimensionsCartesian(w);
  }
  else {
    AdjustDimensionsPolar(w);
  }
}

static void 
ComputeAllDimensions (SciPlotWidget w)
{
  ComputeLegendDimensions(w);
  ComputeDimensions(w);
  ComputeDrawingRange(w);
  AdjustDimensions(w);
}

static void 
ComputeAll (SciPlotWidget w)
{
  ComputeMinMax(w);
  ComputeAllDimensions(w);
}


/*
 * Private drawing routines
 */

static void 
DrawMarker (SciPlotWidget w, real xpaper, real ypaper, real size, int color, int style)
{
  real sizex, sizey;

  switch (style) {
  case XtMARKER_CIRCLE:
    CircleSet(w, xpaper, ypaper, size, color, XtLINE_SOLID);
    break;
  case XtMARKER_FCIRCLE:
    FilledCircleSet(w, xpaper, ypaper, size, color, XtLINE_SOLID);
    break;
  case XtMARKER_SQUARE:
    size -= .5;
    RectSet(w, xpaper - size, ypaper - size,
      xpaper + size, ypaper + size,
      color, XtLINE_SOLID);
    break;
  case XtMARKER_FSQUARE:
    size -= .5;
    FilledRectSet(w, xpaper - size, ypaper - size,
      xpaper + size, ypaper + size,
      color, XtLINE_SOLID);
    break;
  case XtMARKER_UTRIANGLE:
    sizex = size * .866;
    sizey = size / 2.0;
    TriSet(w, xpaper, ypaper - size,
      xpaper + sizex, ypaper + sizey,
      xpaper - sizex, ypaper + sizey,
      color, XtLINE_SOLID);
    break;
  case XtMARKER_FUTRIANGLE:
    sizex = size * .866;
    sizey = size / 2.0;
    FilledTriSet(w, xpaper, ypaper - size,
      xpaper + sizex, ypaper + sizey,
      xpaper - sizex, ypaper + sizey,
      color, XtLINE_SOLID);
    break;
  case XtMARKER_DTRIANGLE:
    sizex = size * .866;
    sizey = size / 2.0;
    TriSet(w, xpaper, ypaper + size,
      xpaper + sizex, ypaper - sizey,
      xpaper - sizex, ypaper - sizey,
      color, XtLINE_SOLID);
    break;
  case XtMARKER_FDTRIANGLE:
    sizex = size * .866;
    sizey = size / 2.0;
    FilledTriSet(w, xpaper, ypaper + size,
      xpaper + sizex, ypaper - sizey,
      xpaper - sizex, ypaper - sizey,
      color, XtLINE_SOLID);
    break;
  case XtMARKER_RTRIANGLE:
    sizey = size * .866;
    sizex = size / 2.0;
    TriSet(w, xpaper + size, ypaper,
      xpaper - sizex, ypaper + sizey,
      xpaper - sizex, ypaper - sizey,
      color, XtLINE_SOLID);
    break;
  case XtMARKER_FRTRIANGLE:
    sizey = size * .866;
    sizex = size / 2.0;
    FilledTriSet(w, xpaper + size, ypaper,
      xpaper - sizex, ypaper + sizey,
      xpaper - sizex, ypaper - sizey,
      color, XtLINE_SOLID);
    break;
  case XtMARKER_LTRIANGLE:
    sizey = size * .866;
    sizex = size / 2.0;
    TriSet(w, xpaper - size, ypaper,
      xpaper + sizex, ypaper + sizey,
      xpaper + sizex, ypaper - sizey,
      color, XtLINE_SOLID);
    break;
  case XtMARKER_FLTRIANGLE:
    sizey = size * .866;
    sizex = size / 2.0;
    FilledTriSet(w, xpaper - size, ypaper,
      xpaper + sizex, ypaper + sizey,
      xpaper + sizex, ypaper - sizey,
      color, XtLINE_SOLID);
    break;
  case XtMARKER_DIAMOND:
    QuadSet(w, xpaper, ypaper - size,
      xpaper + size, ypaper,
      xpaper, ypaper + size,
      xpaper - size, ypaper,
      color, XtLINE_SOLID);
    break;
  case XtMARKER_FDIAMOND:
    FilledQuadSet(w, xpaper, ypaper - size,
      xpaper + size, ypaper,
      xpaper, ypaper + size,
      xpaper - size, ypaper,
      color, XtLINE_SOLID);
    break;
  case XtMARKER_HOURGLASS:
    QuadSet(w, xpaper - size, ypaper - size,
      xpaper + size, ypaper - size,
      xpaper - size, ypaper + size,
      xpaper + size, ypaper + size,
      color, XtLINE_SOLID);
    break;
  case XtMARKER_FHOURGLASS:
    FilledQuadSet(w, xpaper - size, ypaper - size,
      xpaper + size, ypaper - size,
      xpaper - size, ypaper + size,
      xpaper + size, ypaper + size,
      color, XtLINE_SOLID);
    break;
  case XtMARKER_BOWTIE:
    QuadSet(w, xpaper - size, ypaper - size,
      xpaper - size, ypaper + size,
      xpaper + size, ypaper - size,
      xpaper + size, ypaper + size,
      color, XtLINE_SOLID);
    break;
  case XtMARKER_FBOWTIE:
    FilledQuadSet(w, xpaper - size, ypaper - size,
      xpaper - size, ypaper + size,
      xpaper + size, ypaper - size,
      xpaper + size, ypaper + size,
      color, XtLINE_SOLID);
    break;
  case XtMARKER_DOT:
    FilledCircleSet(w, xpaper, ypaper, 1.5, color, XtLINE_SOLID);
    break;

  default:
    break;
  }
}

static void 
DrawLegend (SciPlotWidget w)
{
  real x, y, len, height, height2, len2, ascent;
  int i;
  SciPlotList *p;

  w->plot.current_id = SciPlotDrawingLegend;
  if (w->plot.ShowLegend) {
    x = w->plot.x.LegendPos;
    y = w->plot.y.LegendPos;
    len = (real) w->plot.LegendLineSize;
    len2 = len / 2.0;
    height = FontnumHeight(w, w->plot.axisFont);
    height2 = height / 2.0;
    ascent = FontnumAscent(w, w->plot.axisFont);
    RectSet(w, x, y,
      x + w->plot.x.LegendSize - 1.0 - (real) w->plot.Margin,
      y + w->plot.y.LegendSize - 1.0,
      w->plot.ForegroundColor, XtLINE_SOLID);
    x += (real) w->plot.LegendMargin;
    y += (real) w->plot.LegendMargin;

    for (i = 0; i < w->plot.num_plotlist; i++) {
      p = w->plot.plotlist + i;
      if (p->draw) {
	LineSet(w, x, y + height2, x + len, y + height2,
	  p->LineColor, p->LineStyle);
	DrawMarker(w, x + len2, y + height2, p->markersize,
	  p->PointColor, p->PointStyle);
	TextSet(w, x + len + (real) w->plot.LegendMargin,
	  y + ascent,
	  p->legend, w->plot.ForegroundColor,
	  w->plot.axisFont);
	y += height;
      }
    }
  }
}

static void 
DrawCartesianAxes (SciPlotWidget w)
{
  real x, y, x1, y1, x2, y2, tic, val, height, majorval;
  int j, precision;
  char numberformat[16], label[16];

  w->plot.current_id = SciPlotDrawingAxis;
  height = FontnumHeight(w, w->plot.labelFont);
  x1 = PlotX(w, w->plot.x.DrawOrigin);
  y1 = PlotY(w, w->plot.y.DrawOrigin);
  x2 = PlotX(w, w->plot.x.DrawMax);
  y2 = PlotY(w, w->plot.y.DrawMax);
  LineSet(w, x1, y1, x2, y1, w->plot.ForegroundColor, XtLINE_SOLID);
  LineSet(w, x1, y1, x1, y2, w->plot.ForegroundColor, XtLINE_SOLID);

  precision = w->plot.x.Precision;
  sprintf(numberformat, "%%.%df", precision);
  if (w->plot.XLog) {
    val = w->plot.x.DrawOrigin;
    if (precision > 0)
      precision--;
  }
  else {
    val = w->plot.x.DrawOrigin;
  }
  x = PlotX(w, val);
  if (w->plot.DrawMajorTics)
    LineSet(w, x, y1 + 5, x, y1 - 5, w->plot.ForegroundColor, XtLINE_SOLID);
  if (w->plot.XAxisNumbers) {
    sprintf(label, numberformat, val);
    TextSet(w, x, w->plot.y.AxisPos, label, w->plot.ForegroundColor,
      w->plot.axisFont);
  }
  
  majorval = val;
  while ((majorval * 1.0001) < w->plot.x.DrawMax) {
    if (w->plot.XLog) {

/* Hack to make sure that 9.99999e? still gets interpreted as 10.0000e? */
      if (majorval * 1.1 > w->plot.x.DrawMax)
	break;
      tic = majorval;
      if (w->plot.DrawMinor || w->plot.DrawMinorTics) {
	for (j = 2; j < w->plot.x.MinorNum; j++) {
	  val = tic * (real) j;
	  x = PlotX(w, val);
	  if (w->plot.DrawMinor)
	    LineSet(w, x, y1, x, y2,
	      w->plot.ForegroundColor,
	      XtLINE_WIDEDOT);
	  if (w->plot.DrawMinorTics)
	    LineSet(w, x, y1, x, y1 - 3,
	      w->plot.ForegroundColor,
	      XtLINE_SOLID);
	}
      }
      val = tic * (real) w->plot.x.MinorNum;
      sprintf(numberformat, "%%.%df", precision);
      if (precision > 0)
	precision--;
    }
    else {
      tic = majorval;
      if (w->plot.DrawMinor || w->plot.DrawMinorTics) {
	for (j = 1; j < w->plot.x.MinorNum; j++) {
	  val = tic + w->plot.x.MajorInc * (real) j /
	    w->plot.x.MinorNum;
	  x = PlotX(w, val);
	  if (w->plot.DrawMinor)
	    LineSet(w, x, y1, x, y2,
	      w->plot.ForegroundColor,
	      XtLINE_WIDEDOT);
	  if (w->plot.DrawMinorTics)
	    LineSet(w, x, y1, x, y1 - 3,
	      w->plot.ForegroundColor,
	      XtLINE_SOLID);
	}
      }
      val = tic + w->plot.x.MajorInc;
    }
    x = PlotX(w, val);
    if (w->plot.DrawMajor)
      LineSet(w, x, y1, x, y2, w->plot.ForegroundColor,
	XtLINE_DOTTED);
    else if (w->plot.DrawMinor)
      LineSet(w, x, y1, x, y2, w->plot.ForegroundColor,
	XtLINE_WIDEDOT);
    if (w->plot.DrawMajorTics)
      LineSet(w, x, y1 + 5, x, y1 - 5, w->plot.ForegroundColor,
	XtLINE_SOLID);
    if (w->plot.XAxisNumbers) {
      sprintf(label, numberformat, val);
      TextSet(w, x, w->plot.y.AxisPos, label, w->plot.ForegroundColor,
        w->plot.axisFont);
    }
    majorval = val;
  }
  
  precision = w->plot.y.Precision;
  sprintf(numberformat, "%%.%df", precision);
  if (w->plot.YLog) {
    val = w->plot.y.DrawOrigin;
    if (precision > 0)
      precision--;
  }
  else {
    val = w->plot.y.DrawOrigin;
  }
  y = PlotY(w, val);
  if (w->plot.DrawMajorTics)
    LineSet(w, x1 + 5, y, x1 - 5, y, w->plot.ForegroundColor, XtLINE_SOLID);
  if (w->plot.YAxisNumbers) {
    sprintf(label, numberformat, val);
    if (w->plot.YNumHorz) {
      y+=FontnumHeight(w, w->plot.axisFont)/2.0 -
        FontnumDescent(w, w->plot.axisFont);
      TextSet(w,
        w->plot.x.AxisPos - FontnumTextWidth(w, w->plot.axisFont, label),
        y, label, w->plot.ForegroundColor,
        w->plot.axisFont);
    }
    else {
      VTextSet(w, w->plot.x.AxisPos, y, label, w->plot.ForegroundColor,
        w->plot.axisFont);
    }
  }
  majorval = val;

/* majorval*1.0001 is a fudge to get rid of rounding errors that seem to
 * occur when continuing to add the major axis increment.
 */
  while ((majorval * 1.0001) < w->plot.y.DrawMax) {
    if (w->plot.YLog) {

/* Hack to make sure that 9.99999e? still gets interpreted as 10.0000e? */
      if (majorval * 1.1 > w->plot.y.DrawMax)
	break;
      tic = majorval;
      if (w->plot.DrawMinor || w->plot.DrawMinorTics) {
	for (j = 2; j < w->plot.y.MinorNum; j++) {
	  val = tic * (real) j;
	  y = PlotY(w, val);
	  if (w->plot.DrawMinor)
	    LineSet(w, x1, y, x2, y,
	      w->plot.ForegroundColor,
	      XtLINE_WIDEDOT);
	  if (w->plot.DrawMinorTics)
	    LineSet(w, x1, y, x1 + 3, y,
	      w->plot.ForegroundColor,
	      XtLINE_SOLID);
	}
      }
      val = tic * (real) w->plot.y.MinorNum;
      sprintf(numberformat, "%%.%df", precision);
      if (precision > 0)
	precision--;
    }
    else {
      tic = majorval;
      if (w->plot.DrawMinor || w->plot.DrawMinorTics) {
	for (j = 1; j < w->plot.y.MinorNum; j++) {
	  val = tic + w->plot.y.MajorInc * (real) j /
	    w->plot.y.MinorNum;
	  y = PlotY(w, val);
	  if (w->plot.DrawMinor)
	    LineSet(w, x1, y, x2, y,
	      w->plot.ForegroundColor,
	      XtLINE_WIDEDOT);
	  if (w->plot.DrawMinorTics)
	    LineSet(w, x1, y, x1 + 3, y,
	      w->plot.ForegroundColor,
	      XtLINE_SOLID);
	}
      }
      val = tic + w->plot.y.MajorInc;
    }
    y = PlotY(w, val);
    if (w->plot.DrawMajor)
      LineSet(w, x1, y, x2, y, w->plot.ForegroundColor,
	XtLINE_DOTTED);
    else if (w->plot.DrawMinor)
      LineSet(w, x1, y, x2, y, w->plot.ForegroundColor,
	XtLINE_WIDEDOT);
    if (w->plot.DrawMajorTics)
      LineSet(w, x1 - 5, y, x1 + 5, y, w->plot.ForegroundColor,
	XtLINE_SOLID);
    if (w->plot.YAxisNumbers) {
      sprintf(label, numberformat, val);
      if (w->plot.YNumHorz) {
        y+=FontnumHeight(w, w->plot.axisFont)/2.0 -
          FontnumDescent(w, w->plot.axisFont);
        TextSet(w,
          w->plot.x.AxisPos - FontnumTextWidth(w, w->plot.axisFont, label),
          y, label, w->plot.ForegroundColor,
          w->plot.axisFont);
      }
      else {
        VTextSet(w, w->plot.x.AxisPos, y, label, w->plot.ForegroundColor,
          w->plot.axisFont);
      }
    }
    majorval = val;
  }
  
  if (w->plot.ShowTitle)
    TextSet(w, w->plot.x.TitlePos, w->plot.y.TitlePos,
      w->plot.plotTitle, w->plot.ForegroundColor,
      w->plot.titleFont);
  if (w->plot.ShowXLabel)
    TextCenter(w, w->plot.x.Origin + (w->plot.x.Size / 2.0),
      w->plot.y.LabelPos, w->plot.xlabel,
      w->plot.ForegroundColor, w->plot.labelFont);
  if (w->plot.ShowYLabel)
    VTextCenter(w, w->plot.x.LabelPos,
      w->plot.y.Origin + (w->plot.y.Size / 2.0),
      w->plot.ylabel, w->plot.ForegroundColor,
      w->plot.labelFont);
}

          
static void 
DrawCartesianPlot (SciPlotWidget w)
{
  int i, j, jstart;
  SciPlotList *p;

  w->plot.current_id = SciPlotDrawingAny;
  ClipSet(w);
  w->plot.current_id = SciPlotDrawingLine;
  for (i = 0; i < w->plot.num_plotlist; i++) {
    p = w->plot.plotlist + i;
    if (p->draw) {
      real x1, y1, x2, y2;
      Boolean skipnext=False;
    
      jstart = 0;
      while ((jstart < p->number) &&
        (((p->data[jstart].x <= SCIPLOT_SKIP_VAL ||
           p->data[jstart].y <= SCIPLOT_SKIP_VAL) ||
          (w->plot.XLog && (p->data[jstart].x <= 0.0)) ||
          (w->plot.YLog && (p->data[jstart].y <= 0.0)))))
        jstart++;
      if (jstart < p->number) {
        x1 = PlotX(w, p->data[jstart].x);
        y1 = PlotY(w, p->data[jstart].y);
      }
      for (j = jstart; j < p->number; j++) {
        if (p->data[j].x <= SCIPLOT_SKIP_VAL ||
            p->data[j].y <= SCIPLOT_SKIP_VAL) {
          skipnext=True;
          continue;
        }
        
	if (!((w->plot.XLog && (p->data[j].x <= 0.0)) ||
	    (w->plot.YLog && (p->data[j].y <= 0.0)))) {
	  x2 = PlotX(w, p->data[j].x);
	  y2 = PlotY(w, p->data[j].y);
          if (!skipnext)
            LineSet(w, x1, y1, x2, y2, p->LineColor, p->LineStyle);
	  x1 = x2;
	  y1 = y2;
	}
        
        skipnext=False;
      }
    }
  }
  w->plot.current_id = SciPlotDrawingAny;
  ClipClear(w);
  w->plot.current_id = SciPlotDrawingLine;
  for (i = 0; i < w->plot.num_plotlist; i++) {
    p = w->plot.plotlist + i;
    if (p->draw) {
      real x2, y2;

      for (j = 0; j < p->number; j++) {
	if (!((w->plot.XLog && (p->data[j].x <= 0.0)) ||
	    (w->plot.YLog && (p->data[j].y <= 0.0)) ||
             p->data[j].x <= SCIPLOT_SKIP_VAL ||
             p->data[j].y <= SCIPLOT_SKIP_VAL )) {
	  x2 = PlotX(w, p->data[j].x);
	  y2 = PlotY(w, p->data[j].y);
	  if ((x2 >= w->plot.x.Origin) &&
	    (x2 <= w->plot.x.Origin + w->plot.x.Size) &&
	    (y2 >= w->plot.y.Origin) &&
	    (y2 <= w->plot.y.Origin + w->plot.y.Size)) {

	    DrawMarker(w, x2, y2,
	      p->markersize,
	      p->PointColor,
	      p->PointStyle);
	  }

	}
      }
    }
  }
}

static void 
DrawPolarAxes (SciPlotWidget w)
{
  real x1, y1, x2, y2, max, tic, val, height;
  int i, j;
  char numberformat[16], label[16];

  w->plot.current_id = SciPlotDrawingAxis;
  sprintf(numberformat, "%%.%df", w->plot.x.Precision);
  height = FontnumHeight(w, w->plot.labelFont);
  max = w->plot.PolarScale;
  PlotRTDegrees(w, 0.0, 0.0, &x1, &y1);
  PlotRTDegrees(w, max, 0.0, &x2, &y2);
  LineSet(w, x1, y1, x2, y2, 1, XtLINE_SOLID);
  for (i = 45; i < 360; i += 45) {
    PlotRTDegrees(w, max, (real) i, &x2, &y2);
    LineSet(w, x1, y1, x2, y2, w->plot.ForegroundColor, XtLINE_DOTTED);
  }
  for (i = 1; i <= w->plot.x.MajorNum; i++) {
    tic = w->plot.PolarScale *
      (real) i / (real) w->plot.x.MajorNum;
    if (w->plot.DrawMinor || w->plot.DrawMinorTics) {
      for (j = 1; j < w->plot.x.MinorNum; j++) {
	val = tic - w->plot.x.MajorInc * (real) j /
	  w->plot.x.MinorNum;
	PlotRTDegrees(w, val, 0.0, &x2, &y2);
	if (w->plot.DrawMinor)
	  CircleSet(w, x1, y1, x2 - x1,
	    w->plot.ForegroundColor, XtLINE_WIDEDOT);
	if (w->plot.DrawMinorTics)
	  LineSet(w, x2, y2 - 2.5, x2, y2 + 2.5,
	    w->plot.ForegroundColor, XtLINE_SOLID);
      }
    }
    PlotRTDegrees(w, tic, 0.0, &x2, &y2);
    if (w->plot.DrawMajor)
      CircleSet(w, x1, y1, x2 - x1, w->plot.ForegroundColor, XtLINE_DOTTED);
    if (w->plot.DrawMajorTics)
      LineSet(w, x2, y2 - 5.0, x2, y2 + 5.0, w->plot.ForegroundColor, XtLINE_SOLID);
    if (w->plot.XAxisNumbers) {
      sprintf(label, numberformat, tic);
      TextSet(w, x2, y2 + height, label, w->plot.ForegroundColor, w->plot.axisFont);
    }
  }
  
  if (w->plot.ShowTitle)
    TextSet(w, w->plot.x.TitlePos, w->plot.y.TitlePos,
      w->plot.plotTitle, w->plot.ForegroundColor, w->plot.titleFont);
}

static void 
DrawPolarPlot (SciPlotWidget w)
{
  int i, j;
  SciPlotList *p;

  w->plot.current_id = SciPlotDrawingLine;
  for (i = 0; i < w->plot.num_plotlist; i++) {
    p = w->plot.plotlist + i;
    if (p->draw) {
      int jstart;
      real x1, y1, x2, y2;
      Boolean skipnext=False;

      jstart = 0;
      while ((jstart < p->number) &&
        (p->data[jstart].x <= SCIPLOT_SKIP_VAL ||
          p->data[jstart].y <= SCIPLOT_SKIP_VAL))
        jstart++;
      if (jstart < p->number) {
        PlotRT(w, p->data[0].x, p->data[0].y, &x1, &y1);
      }
      for (j = jstart; j < p->number; j++) {
        if (p->data[j].x <= SCIPLOT_SKIP_VAL ||
            p->data[j].y <= SCIPLOT_SKIP_VAL) {
          skipnext=True;
          continue;
        }
        
	PlotRT(w, p->data[j].x, p->data[j].y, &x2, &y2);
        if (!skipnext) {
          LineSet(w, x1, y1, x2, y2,
            p->LineColor, p->LineStyle);
          DrawMarker(w, x1, y1, p->markersize,
            p->PointColor, p->PointStyle);
          DrawMarker(w, x2, y2, p->markersize,
            p->PointColor, p->PointStyle);
        }
	x1 = x2;
	y1 = y2;
        
        skipnext=False;
      }
    }
  }
}

static void 
DrawAll (SciPlotWidget w)
{
  if (w->plot.ChartType == XtCARTESIAN) {
    DrawCartesianAxes(w);
    DrawLegend(w);
    DrawCartesianPlot(w);
  }
  else {
    DrawPolarAxes(w);
    DrawLegend(w);
    DrawPolarPlot(w);
  }
}

static Boolean 
DrawQuick (SciPlotWidget w)
{
  Boolean range_check;

  range_check = CheckMinMax(w);
  EraseClassItems(w, SciPlotDrawingLine);
  EraseAllItems(w);
  DrawAll(w);
  
  return range_check;
}


/*
 * Public Plot functions
 */

int 
SciPlotAllocNamedColor (Widget wi, char *name)
{
  XColor used, exact;
  SciPlotWidget w;

  if (!XtIsSciPlot(wi))
    return -1;

  w = (SciPlotWidget) wi;

  if (!XAllocNamedColor(XtDisplay(w), w->plot.cmap, name, &used, &exact))
    return 1;
  return ColorStore(w, used.pixel);
}

int 
SciPlotAllocRGBColor (Widget wi, int r, int g, int b)
{
  XColor used;
  SciPlotWidget w;

  if (!XtIsSciPlot(wi))
    return -1;

  w = (SciPlotWidget) wi;

  used.pixel = 0;
  r *= 256;
  g *= 256;
  b *= 256;
  if (r > 65535)
    r = 65535;
  if (g > 65535)
    g = 65535;
  if (b > 65535)
    b = 65535;
  used.red = (unsigned short) r;
  used.green = (unsigned short) g;
  used.blue = (unsigned short) b;
  if (!XAllocColor(XtDisplay(w), w->plot.cmap, &used))
    return 1;
  return ColorStore(w, used.pixel);
}

void 
SciPlotSetBackgroundColor (Widget wi, int color)
{
  SciPlotWidget w;

  if (!XtIsSciPlot(wi))
    return;

  w = (SciPlotWidget) wi;
  if (color < w->plot.num_colors) {
    w->plot.BackgroundColor = color;
    w->core.background_pixel = w->plot.colors[color];
    XSetWindowBackground( XtDisplay(w), XtWindow(w), w->core.background_pixel);
  }
}

void 
SciPlotSetForegroundColor (Widget wi, int color)
{
  SciPlotWidget w;

  if (!XtIsSciPlot(wi))
    return;

  w = (SciPlotWidget) wi;
  if (color < w->plot.num_colors)
    w->plot.ForegroundColor = color;
}

void 
SciPlotListDelete (Widget wi, int idnum)
{
  SciPlotList *p;
  SciPlotWidget w;

  if (!XtIsSciPlot(wi))
    return;

  w = (SciPlotWidget) wi;

  p = _ListFind(w, idnum);
  if (p)
    _ListDelete(p);
}

int 
SciPlotListCreateFromData (Widget wi, int num, real *xlist, real *ylist, char *legend, int pcolor, int pstyle, int lcolor, int lstyle)
{
  int idnum;
  SciPlotList *p;
  SciPlotWidget w;

  if (!XtIsSciPlot(wi))
    return -1;

  w = (SciPlotWidget) wi;

  idnum = _ListNew(w);
  p = w->plot.plotlist + idnum;
  _ListSetReal(p, num, xlist, ylist);
  _ListSetLegend(p, legend);
  _ListSetStyle(p, pcolor, pstyle, lcolor, lstyle);
  return idnum;
}

int 
SciPlotListCreateFloat (Widget wi, int num, float *xlist, float *ylist, char *legend)
{
  int idnum;
  SciPlotList *p;
  SciPlotWidget w;

  if (!XtIsSciPlot(wi))
    return -1;

  w = (SciPlotWidget) wi;

  idnum = _ListNew(w);
  p = w->plot.plotlist + idnum;
  _ListSetFloat(p, num, xlist, ylist);
  _ListSetLegend(p, legend);
  _ListSetStyle(p, 1, XtMARKER_CIRCLE, 1, XtLINE_SOLID);
  return idnum;
}

void 
SciPlotListUpdateFloat (Widget wi, int idnum, int num, float *xlist, float *ylist)
{
  SciPlotList *p;
  SciPlotWidget w;

  if (!XtIsSciPlot(wi))
    return;

  w = (SciPlotWidget) wi;

  p = _ListFind(w, idnum);
  if (p)
    _ListSetFloat(p, num, xlist, ylist);
}

void 
SciPlotListAddFloat (Widget wi, int idnum, int num, float *xlist, float *ylist)
{
  SciPlotList *p;
  SciPlotWidget w;

  if (!XtIsSciPlot(wi))
    return;

  w = (SciPlotWidget) wi;

  p = _ListFind(w, idnum);
  if (p)
    _ListAddFloat(p, num, xlist, ylist);
}

int 
SciPlotListCreateDouble (Widget wi, int num, double *xlist, double *ylist, char *legend)
{
  int idnum;
  SciPlotList *p;
  SciPlotWidget w;

  if (!XtIsSciPlot(wi))
    return -1;

  w = (SciPlotWidget) wi;

  idnum = _ListNew(w);
  p = w->plot.plotlist + idnum;
  _ListSetDouble(p, num, xlist, ylist);
  _ListSetLegend(p, legend);
  _ListSetStyle(p, 1, XtMARKER_CIRCLE, 1, XtLINE_SOLID);
  return idnum;
}

void 
SciPlotListUpdateDouble (Widget wi, int idnum, int num, double *xlist, double *ylist)
{
  SciPlotList *p;
  SciPlotWidget w;

  if (!XtIsSciPlot(wi))
    return;

  w = (SciPlotWidget) wi;

  p = _ListFind(w, idnum);
  if (p)
    _ListSetDouble(p, num, xlist, ylist);
}

void 
SciPlotListAddDouble (Widget wi, int idnum, int num, double *xlist, double *ylist)
{
  SciPlotList *p;
  SciPlotWidget w;

  if (!XtIsSciPlot(wi))
    return;

  w = (SciPlotWidget) wi;

  p = _ListFind(w, idnum);
  if (p)
    _ListAddDouble(p, num, xlist, ylist);
}

void 
SciPlotListSetStyle (Widget wi, int idnum, int pcolor, int pstyle, int lcolor, int lstyle)
{
  SciPlotList *p;
  SciPlotWidget w;

  if (!XtIsSciPlot(wi))
    return;

  w = (SciPlotWidget) wi;

  p = _ListFind(w, idnum);
  if (p)
    _ListSetStyle(p, pcolor, pstyle, lcolor, lstyle);
}

void 
SciPlotListSetMarkerSize (Widget wi, int idnum, float size)
{
  SciPlotList *p;
  SciPlotWidget w;

  if (!XtIsSciPlot(wi))
    return;

  w = (SciPlotWidget) wi;

  p = _ListFind(w, idnum);
  if (p)
    p->markersize=size;
}

void 
SciPlotSetXAutoScale (Widget wi)
{
  SciPlotWidget w;

  if (!XtIsSciPlot(wi))
    return;

  w = (SciPlotWidget) wi;
  w->plot.XAutoScale = True;
}

void 
SciPlotSetXUserScale (Widget wi, double min, double max)
{
  SciPlotWidget w;

  if (!XtIsSciPlot(wi))
    return;

  w = (SciPlotWidget) wi;
  if (min < max) {
    w->plot.XAutoScale = False;
    w->plot.UserMin.x = (real) min;
    w->plot.UserMax.x = (real) max;
  }
}

void 
SciPlotSetYAutoScale (Widget wi)
{
  SciPlotWidget w;

  if (!XtIsSciPlot(wi))
    return;

  w = (SciPlotWidget) wi;
  w->plot.YAutoScale = True;
}

void 
SciPlotSetYUserScale (Widget wi, double min, double max)
{
  SciPlotWidget w;

  if (!XtIsSciPlot(wi))
    return;

  w = (SciPlotWidget) wi;
  if (min < max) {
    w->plot.YAutoScale = False;
    w->plot.UserMin.y = (real) min;
    w->plot.UserMax.y = (real) max;
  }
}

void 
SciPlotPrintStatistics (Widget wi)
{
  int i, j;
  SciPlotList *p;
  SciPlotWidget w;

  if (!XtIsSciPlot(wi))
    return;

  w = (SciPlotWidget) wi;

  printf("Title=%s\nxlabel=%s\tylabel=%s\n",
    w->plot.plotTitle, w->plot.xlabel, w->plot.ylabel);
  printf("ChartType=%d\n", w->plot.ChartType);
  printf("Degrees=%d\n", w->plot.Degrees);
  printf("XLog=%d\tYLog=%d\n", w->plot.XLog, w->plot.YLog);
  printf("XAutoScale=%d\tYAutoScale=%d\n",
    w->plot.XAutoScale, w->plot.YAutoScale);
  for (i = 0; i < w->plot.num_plotlist; i++) {
    p = w->plot.plotlist + i;
    if (p->draw) {
      printf("\nLegend=%s\n", p->legend);
      printf("Styles: point=%d line=%d  Color: point=%d line=%d\n",
	p->PointStyle, p->LineStyle, p->PointColor, p->LineColor);
      for (j = 0; j < p->number; j++)
	printf("%f\t%f\n", p->data[j].x, p->data[j].y);
      printf("\n");
    }
  }
}

void 
SciPlotExportData (Widget wi, FILE *fd)
{
  int i, j;
  SciPlotList *p;
  SciPlotWidget w;

  if (!XtIsSciPlot(wi))
    return;

  w = (SciPlotWidget) wi;

  fprintf(fd, "Title=\"%s\"\n", w->plot.plotTitle);
  fprintf(fd, "Xaxis=\"%s\"\n", w->plot.xlabel);
  fprintf(fd, "Yaxis=\"%s\"\n\n", w->plot.ylabel);
  for (i = 0; i < w->plot.num_plotlist; i++) {
    p = w->plot.plotlist + i;
    if (p->draw) {
      fprintf(fd, "Line=\"%s\"\n",p->legend);
      for (j = 0; j < p->number; j++)
	fprintf(fd, "%e\t%e\n", p->data[j].x, p->data[j].y);
      fprintf(fd, "\n");
    }
  }
}

int 
SciPlotStoreAllocatedColor(Widget wi, Pixel p)
{
  SciPlotWidget w;
  
  if (!XtIsSciPlot(wi))
    return -1;
  
  w = (SciPlotWidget) wi;
  
  return ColorStore(w, p);
}

void 
SciPlotUpdate (Widget wi)
{
  SciPlotWidget w;

  if (!XtIsSciPlot(wi))
    return;

  w = (SciPlotWidget) wi;
  EraseAll(w);
#ifdef DEBUG_SCIPLOT
  SciPlotPrintStatistics(w);
#endif
  ComputeAll(w);
  DrawAll(w);
}

Boolean 
SciPlotQuickUpdate (Widget wi)
{
  SciPlotWidget w;

  if (!XtIsSciPlot(wi))
    return False;
  
  w = (SciPlotWidget) wi;
  return DrawQuick(w);
}
