/* XLISP-STAT 2.1 Copyright (c) 1990, by Luke Tierney                  */
/* Additions to Xlisp 2.1, Copyright (c) 1989 by David Michael Betz    */
/* You may give out copies of this software; for conditions see the    */
/* file COPYING included with this distribution.                       */

#include "xlisp.h"
#include "xlstat.h"

/**************************************************************************/
/**************************************************************************/
/**                                                                      **/
/**                      Fixed Point Arithmetic Package                  **/
/**                                                                      **/
/**************************************************************************/
/**************************************************************************/

#define SCALE 65536

#ifdef MACINTOSH
typedef struct { short h; unsigned short v; } fixed_struct;
static FixRound(Fixed x) { return(((fixed_struct *) &x)->h); }

#define INTPART(x)  (((fixed_struct *) (x))->h)
#define FRACPART(x) (((fixed_struct *) (x))->v)

static Fixed FixInnerProduct(int vars, Fixed *x, Fixed *y, int *inbasis)
{
  register Fixed result = 0, hx, lx, hy, ly;
  
  for (; vars-- > 0; x++, y++) 
    if (*inbasis++) {
      hx = INTPART(x); lx = FRACPART(x);
      hy = INTPART(y); ly = FRACPART(y);
      if (hx == 0) result += *x * hy + ((*x * (ly >> 2)) >> 14);
      else result += *x * hy + hx * ly + ((lx * (ly >> 2)) >> 14);
    }
    
  return(result);
}

#else
#define FixRound(x) ((int) ((x) / SCALE))

#ifdef MSDOS
static Fixed FixInnerProduct(int vars, Fixed *x, Fixed *y, int *inbasis)
{
  register unsigned int pos;
  register Fixed result = 0, val, xx, yy, hx, lx, hy, ly;

  for (; vars-- > 0; x++, y++)
    if (*inbasis++) {
      pos = TRUE;
      xx = *x;
      if (xx < 0) { pos = FALSE; xx = -xx; }
      yy = *y;
      if (yy < 0) { pos = ! pos; yy = -yy; }

      lx = LOWORD(xx); hx = HIWORD(xx);
      ly = LOWORD(yy); hy = HIWORD(yy);
      val = xx * hy + ((lx * (ly >> 2)) >> 14);
      if (hx) val += hx * ly;
      if (pos) result += val;
      else result -= val;
    }

  return(result);
}
#else
static Fixed FixInnerProduct P4C(int, vars, Fixed *, x, Fixed *, y, int *, inbasis)
{
  double result = 0.0;
  
  for (; vars-- > 0; x++, y++) 
    if (*inbasis++) result += ((double) *x) * ((double) *y);
    
  return((Fixed) (result / SCALE));
}
#endif /* MSDOS */
#endif /* MACINTOSH */

#define Int2Fixed(x) ((Fixed)((x) * SCALE))
#define Double2Fixed(x) ((Fixed) ((x) * SCALE))
#define Fixed2Double(x) (((double) (x)) / SCALE)

/**************************************************************************/
/**************************************************************************/
/**                                                                      **/
/**                         IViewBasicPoints Package                     **/
/**                                                                      **/
/**************************************************************************/
/**************************************************************************/

/* forward declarations */
LOCAL double IViewBasicPointValue P3H(IViewBasicPoints, unsigned, unsigned);


/**************************************************************************/
/**                                                                      **/
/**            Basic Points Creation and Destruction Functions           **/
/**                                                                      **/
/**************************************************************************/

static IViewBasicPoints IViewNewBasicPoints P3C(int, m, double *, scale, double *, location)
{
  IViewBasicPoints p;
  
  p = (IViewBasicPoints) StCalloc(sizeof(struct basic_points), 1);
  
  p->num_points = 0;
  p->num_variables = m;
  p->scale = scale;
  p->location = location;
  p->recalculateScreenPoints = FALSE;
  p->transformation = (double **) NULL;

  if (m > 0) {
    p->data = (IViewReallocData *) StCalloc(sizeof(IViewReallocData), m);
    p->screen_data = (IViewReallocData *) StCalloc(sizeof(IViewReallocData), m);    
  }

  return(p);
}

static VOID IViewFreeBasicPoints P1C(IViewBasicPoints, p)
{
  int i;
  
  for (i = 0; i < p->num_variables; i++) {
    if (p->data != NULL) StRFree(p->data[i]);
    if (p->screen_data != NULL) StRFree(p->screen_data[i]);
  }
  
  StFree(p->data);
  StFree(p->screen_data);
  StFree(p);
}

static VOID IViewAddBasicPoints P2C(IViewBasicPoints, p, int, n)
{
  int size, i;

  size = p->num_points + n;
  if (p->num_variables > 0) {
    if (p->data == NULL || p->screen_data == NULL) return;

    for (i = 0; i < p->num_variables; i++) {
      p->data[i] = StRRealloc(p->data[i], sizeof(double), size);
      p->screen_data[i] = StRRealloc(p->screen_data[i], sizeof(Fixed), size);
    }
  }
  p->num_points += n;
}

static VOID IViewClearBasicPoints P1C(IViewBasicPoints, p)
{
  int i;
  p->num_points = 0;
  if (p->data == NULL || p->screen_data == NULL) return;

  for (i = 0; i < p->num_variables; i++) {
    StRFree(p->data[i]);
    p->data[i] = NULL;
    StRFree(p->screen_data[i]);
    p->screen_data[i] = NULL;
  }
}

/**************************************************************************/
/**                                                                      **/
/**       Basic Points Data Set Access and Modificaiton Functions        **/
/**                                                                      **/
/**************************************************************************/

static int IViewBasicPointsNumPoints P1C(IViewBasicPoints, p)
{
  return(p->num_points);
}

static int IViewBasicPointsNumVariables P1C(IViewBasicPoints, p)
{
  return(p->num_variables);
}

static VOID IViewBasicPointsSetRecalculate P2C(IViewBasicPoints, p, int, fixed)
{
  p->recalculateScreenPoints = TRUE;
  p->fixed = fixed;
}

static double TransformedValue P3C(IViewBasicPoints, p, unsigned, var, unsigned, point)
{
  double x, a;
  int i;
  
  if (p->transformation == NULL) 
    return(IViewBasicPointValue(p, var, point));
  else {
    for (i = 0, x = 0.0; i < p->num_variables; i++)
      if ((a = p->transformation[var][i]) != 0.0)
        x += IViewBasicPointValue(p, i, point) * a;
    return(x);
  }
}

static VOID SetScreenValue P3C(IViewBasicPoints, p, unsigned, var, unsigned, point)
{
  double x = TransformedValue(p, var, point);
  Fixed screen_x, *screen_data;
  
  if (p->screen_data == NULL) return;
  screen_data = (Fixed *) StRPtr(p->screen_data[var]);
  if (screen_data == NULL) return;

  if (p->location == NULL || p->scale == NULL) x = 0.0;
  else x = x * p->scale[var] + p->location[var];
  
  screen_x = Double2Fixed(x);
  screen_data[point] = screen_x;
}

static VOID RecalculateScreenPoints P1C(IViewBasicPoints, p)
{
  int var, point;
  
  for (var = 0; var < p->num_variables; var++)
    for (point = 0; point < p->num_points; point++) 
      SetScreenValue(p, var, point);
  p->recalculateScreenPoints = FALSE;
}

static VOID IViewBasicPointsSetTransformation P2C(IViewBasicPoints, p, double **, a)
{
  p->transformation = a;
  p->recalculateScreenPoints = TRUE;
}  

static VOID IViewBasicPointsApplyTransformation P3C(IViewBasicPoints, p,
                                                    double **, a, int *, inbasis)
{
  static maxvars = 0;
  static Fixed **b, *x, **screen_data, *screen_location;
  int vars, n, i, j;
  double *scale = p->scale, *location = p->location;
  if (p->screen_data == NULL) return;

  vars = p->num_variables;
  n = p->num_points;

  /* allocate local working storage */
  if (maxvars < vars) {
    maxvars = vars;
    if (b != NULL) StFree(b[0]);
    StFree(b);
    StFree(x);
    StFree(screen_data);
    StFree(screen_location);
    b = (Fixed **) StCalloc(sizeof(Fixed *), maxvars);
    b[0] = (Fixed *) StCalloc(sizeof(Fixed), maxvars * maxvars);
    for (i = 1; i < maxvars; i++) b[i] = b[0] + i * maxvars;
    x = (Fixed *) StCalloc(sizeof(Fixed), maxvars);
    screen_data = (Fixed **) StCalloc(sizeof(Fixed *), maxvars);
    screen_location = (Fixed *) StCalloc(sizeof(Fixed), maxvars);
  }
  
  /* convert transformation to fixed point format*/ 
  if (p->fixed) {
    for (i = 0; i < vars; i++)
      if (inbasis[i])
        for (j = 0; j < vars; j++)
          if (inbasis[j]) b[i][j] = Double2Fixed(a[i][j]);
  }
  else {
    for (i = 0; i < vars; i++)
      if (inbasis[i]) {
        for (j = 0; j < vars; j++)
          if (inbasis[j]) 
            b[i][j] = Double2Fixed(scale[i] * a[i][j] / scale[j]);
        screen_location[i] = Double2Fixed(location[i]);
      }
  }
  
  /* set up array with screen coordinates */
  for (i = 0; i < vars; i++)
    screen_data[i] = (Fixed *) StRPtr(p->screen_data[i]);
  if (! p->fixed)
    for (i = 0; i < vars; i++) 
      if (inbasis[i]) 
        for (j = 0; j < n; j++) screen_data[i][j] -= screen_location[i];
    
  /* apply the transformation */
  for (i = 0; i < n; i++) {
    for (j = 0; j < vars; j++) 
      if (inbasis[j]) x[j] = screen_data[j][i];    
    for (j = 0; j < vars; j++) 
      if (inbasis[j]) {
        screen_data[j][i] = FixInnerProduct(vars, b[j], x, inbasis);
      }
  }

  /* adjust origins if scaling is not fixed */
  if (! p->fixed)
    for (i = 0; i < vars; i++) 
      if (inbasis[i]) 
        for (j = 0; j < n; j++) screen_data[i][j] += screen_location[i];
}

/**************************************************************************/
/**                                                                      **/
/**         Basic Points Point Access and Modification Functions         **/
/**                                                                      **/
/**************************************************************************/

static VOID IViewBasicPointSetValue P4C(IViewBasicPoints, p,
                                        unsigned, var, unsigned, point,
                                        double, value)
{
  double *x;
  
  if (var < p->num_variables && point < p->num_points && p->data != NULL) {
    x = (double *) StRPtr(p->data[var]);
    if (x != NULL) x[point] = value;
  }
  if (p->transformation != NULL) p->recalculateScreenPoints = TRUE;
  if (! p->recalculateScreenPoints) SetScreenValue(p, var, point);
}

static double IViewBasicPointValue P3C(IViewBasicPoints, p,
                                       unsigned, var, unsigned, point)
{
  double *x, value;
  
  if (var < p->num_variables  && point < p->num_points && p->data != NULL) {
    x = (double *) StRPtr(p->data[var]);
    value = (x != NULL) ? x[point] : 0.0;
    return(value);
  }
  else xlfail("index out of range");
  return 0.0; /* not reached */
}

static int IViewBasicPointScreenValue P3C(IViewBasicPoints, p,
                                          unsigned, var, unsigned, point)
{
  Fixed *screen_data;
  
  if (p->recalculateScreenPoints) RecalculateScreenPoints(p);
  
  if (var < p->num_variables && point < p->num_points 
      && p->screen_data != NULL) {
    screen_data = (Fixed *) StRPtr(p->screen_data[var]);
#ifdef PERSPECTIVE
    return(PerspScreenValue(p, var, point));
#else
    return(FixRound(screen_data[point]));
#endif /* PERSPECTIVE */
  }
  else xlfail("index out of range");
  return 0; /* not reached */
}

static VOID IViewBasicPointsGetScreenValues P3C(IViewBasicPoints, p, unsigned, point, int *, x)
{
  int i, n, vars;
  Fixed *screen_data;
  
  n = p->num_points;
  vars = p->num_variables;

  if (p->recalculateScreenPoints) RecalculateScreenPoints(p);
  if (p->screen_data == NULL || point >= n) return;
  
  for (i = 0; i < vars; i++){
    screen_data = (Fixed *) StRPtr(p->screen_data[i]);
    if (screen_data != NULL) x[i] = FixRound(screen_data[point]);
  }
}

/**************************************************************************/
/**************************************************************************/
/**                                                                      **/
/**                            IViewData Package                         **/
/**                                                                      **/
/**************************************************************************/
/**************************************************************************/

VOID IViewDataSetPointColor P3H(IViewData, unsigned, int);
VOID IViewDataSetPointState P3H(IViewData, unsigned, int);
VOID IViewDataSetPointSymbol P4H(IViewData, unsigned, int, int);
VOID IViewDataSetLineValue P4H(IViewData, int, int, double);
VOID IViewDataSetLineColor P3H(IViewData, unsigned, int);
VOID IViewDataSetLineWidth P3H(IViewData, unsigned, unsigned);
VOID IViewDataSetNextLine P3H(IViewData, unsigned, int);
VOID IViewDataSetLineType P3H(IViewData, unsigned, int);

/**************************************************************************/
/**                                                                      **/
/**          IView Data Construction and Destruction Functions           **/
/**                                                                      **/
/**************************************************************************/

IViewData IViewDataNew P1C(int, vars)
{
  IViewData p;
  
  p = (IViewData) StCalloc(sizeof(struct iview_data), 1);
  if (vars > 0) {
    p->mins = (double *) StCalloc(sizeof(double), vars);
    p->maxes = (double *) StCalloc(sizeof(double), vars);
    p->scale = (double *) StCalloc(sizeof(double), vars);
    p->location = (double *) StCalloc(sizeof(double), vars);
    p->screen_mins = (int *) StCalloc(sizeof(int), vars);
    p->screen_maxes = (int *) StCalloc(sizeof(int), vars);
  }
  
  p->points = IViewNewBasicPoints(vars, p->scale, p->location);
  p->lines = IViewNewBasicPoints(vars, p->scale, p->location);
#ifdef USESTRINGS
  p->strings = IViewNewBasicPoints(vars, p->scale, p->location);
#endif /* USESTRINGS */
  if (vars > 0)
    p->variableLabels = (char **) StCalloc(sizeof(char *), vars);
  p->recalculateScreenPoints = FALSE;
  p->transformed = FALSE;
  
  return(p);
}

VOID IViewDataFree P1C(IViewData, p)
{
  int i;
  PointInfo *pointInfo;
#ifdef USESTRINGS
  StringInfo *stringInfo;
#endif /* USESTRINGS */
  
  StFree(p->mins);
  StFree(p->maxes);
  StFree(p->scale);
  StFree(p->location);
  StFree(p->screen_mins);
  StFree(p->screen_maxes);

  for (i = 0; i < p->points->num_points; i++) {
    pointInfo = (PointInfo *) StRPtr(p->pointInfo);
    if (pointInfo[i].label != NULL) StFree(pointInfo[i].label);
  }
  StRFree(p->pointInfo);
  
  StRFree(p->lineInfo);
  
#ifdef USESTRINGS
  for (i = 0; i < p->strings->num_points; i++) {
    stringInfo = (StringInfo *) StRPtr(p->stringInfo);
    if (stringInfo[i].string != NULL) StFree(stringInfo[i].string);
  }
  StRFree(p->stringInfo);
#endif /* USESTRINGS */

  for (i = 0; i < p->points->num_variables; i++) {
    if (p->variableLabels[i] != NULL) StFree(p->variableLabels[i]);
  }
  StFree(p->variableLabels);
    
  IViewFreeBasicPoints(p->points);
  IViewFreeBasicPoints(p->lines);
#ifdef USESTRINGS
  IViewFreeBasicPoints(p->strings);
#endif /* USESTRINGS */
  
  if (p->transformation != NULL) {
    StFree(p->transformation[0]);
    StFree(p->transformation);
  }
  StFree(p);
}

LOCAL IViewBasicPoints IViewDataPoints P1C(IViewData, data)
{
  if (data == NULL) xlfail("nil data pointer");
  if (data->points == NULL) xlfail("nil point data pointer");
  return(data->points);
}

LOCAL IViewBasicPoints IViewDataLines P1C(IViewData, data)
{
  if (data == NULL) xlfail("nil data pointer");
  if (data->lines == NULL) xlfail("nil line data pointer");
  return(data->lines);
}

#ifdef USESTRINGS
LOCAL IViewBasicPoints IViewDataStrings P1C(IViewData, data)
{
  if (data == NULL) xlfail("nil data pointer");
  if (data->strings == NULL) xlfail("nil string data pointer");
  return(data->strings);
}
#endif /* USESTRINGS */

/**************************************************************************/
/**                                                                      **/
/**                        General Data Functions                        **/
/**                                                                      **/
/**************************************************************************/

int IViewDataNumVariables P1C(IViewData, p)
{
  return(IViewBasicPointsNumVariables(IViewDataPoints(p)));
}

VOID IViewDataSetVariableLabel P3C(IViewData, p, unsigned, var, char *, s)
{
  if (p == NULL || var >= IViewDataNumVariables(p)) return;
  
  StFree(p->variableLabels[var]);
  p->variableLabels[var] = NULL;
  if (s != 0 && strlen(s) != 0) {
    p->variableLabels[var] = StCalloc(sizeof(char), 1 + strlen(s));
    strcpy(p->variableLabels[var], s);
  }
}

char *IViewDataVariableLabel P2C(IViewData, p, unsigned, var)
{
  if (p == NULL || var >= IViewDataNumVariables(p)) return(NULL);
  return(p->variableLabels[var]);
}

static int CalculateLocationScale P1C(IViewData, p)
{
  int i, fixed = 0, vars = IViewDataNumVariables(p);
  double range, screen_range, scale;
  
  for (i = 0; i < vars; i++) {
    range = p->maxes[i] - p->mins[i];
    screen_range = p->screen_maxes[i] - p->screen_mins[i];
    p->scale[i] = (range > 0) ? screen_range / range : 0.0;
    p->location[i] = p->screen_mins[i] - p->mins[i] * p->scale[i];
  }
  if (vars > 0) {
    fixed = (p->location[0] == 0.0) ? TRUE : FALSE;
    scale = p->scale[0];
    for (i = 1; i < vars; i++)
      fixed = (fixed && scale == p->scale[i] && p->location[i] == 0.0);
  }
  return(fixed);
}

VOID IViewDataSetRange P4C(IViewData, p, unsigned, var, double, low, double, high)
{
  int fixed;
  
  if (p != NULL && var < IViewDataNumVariables(p) && low < high) {
    p->mins[var] = low;
    p->maxes[var] = high;
    fixed = CalculateLocationScale(p);
    IViewBasicPointsSetRecalculate(p->points, fixed);
    IViewBasicPointsSetRecalculate(p->lines, fixed);
#ifdef USESTRINGS
    IViewBasicPointsSetRecalculate(p->strings, fixed);
#endif /* USESTRINGS */
  }
}

VOID IViewDataGetRange P4C(IViewData, p, unsigned, var, double *, low, double *, high)
{
  if (p != NULL && var < IViewDataNumVariables(p)) {
    if (low != NULL) *low = p->mins[var];
    if (high != NULL) *high = p->maxes[var];
  }
}

VOID IViewDataSetScreenRange P4C(IViewData, p, unsigned, var, int, low, int, high)
{
  int fixed;
  
  if (p != NULL && var < IViewDataNumVariables(p) && low < high) {
    p->screen_mins[var] = low;
    p->screen_maxes[var] = high;
    fixed = CalculateLocationScale(p);
    IViewBasicPointsSetRecalculate(IViewDataPoints(p), fixed);
    IViewBasicPointsSetRecalculate(IViewDataLines(p), fixed);
#ifdef USESTRINGS
    IViewBasicPointsSetRecalculate(IViewDataStrings(p), fixed);
#endif /* USESTRINGS */
  }
}

VOID IViewDataGetScreenRange P4C(IViewData, p, unsigned, var, int *, low, int *, high)
{
  if (p != NULL && var < IViewDataNumVariables(p)) {
    if (low != NULL) *low = p->screen_mins[var];
    if (high != NULL) *high = p->screen_maxes[var];
  }
}

VOID IViewDataSetIdentityTransformation P1C(IViewData, data)
{
  int i, j, vars = IViewDataNumVariables(data);
  double *p;
  
  if (data == NULL) return;
  
  data->transformed = FALSE;
  if (data->transformation == NULL) {
    data->transformation = (double **) StCalloc(sizeof(double *), vars);
    p = (double *) StCalloc(sizeof(double), vars * vars);
    for (i = 0; i < vars; i++)
      data->transformation[i] = p + i * vars;
  }
  
  for (i = 0; i < vars; i++)
    for (j = 0; j < vars; j++)
      data->transformation[i][j] = (i == j) ? 1.0 : 0.0;

  IViewBasicPointsSetTransformation(IViewDataPoints(data), data->transformation);
  IViewBasicPointsSetTransformation(IViewDataLines(data), data->transformation);
#ifdef USESTRINGS
  IViewBasicPointsSetTransformation(IViewDataStrings(data), data->transformation);
#endif /* USESTRINGS */
}

VOID IViewDataSetTransformation P2C(IViewData, data, double **, a)
{
  int i, j, vars = IViewDataNumVariables(data);
  double *p;
  
  if (data == NULL) return;
  data->transformed = TRUE;
  if (a != NULL) {
    if (data->transformation == NULL) {
      data->transformation = (double **) StCalloc(sizeof(double *), vars);
      p = (double *) StCalloc(sizeof(double), vars * vars);
      for (i = 0; i < vars; i++)
        data->transformation[i] = p + i * vars;
    }
  
    for (i = 0; i < vars; i++)
      for (j = 0; j < vars; j++)
        data->transformation[i][j] = a[i][j];
  }
  else if (data->transformation != NULL) {
    StFree(data->transformation[0]);
    StFree(data->transformation);
  }

  IViewBasicPointsSetTransformation(IViewDataPoints(data), data->transformation);
  IViewBasicPointsSetTransformation(IViewDataLines(data), data->transformation);
#ifdef USESTRINGS
  IViewBasicPointsSetTransformation(IViewDataStrings(data), data->transformation);
#endif /* USESTRINGS */
}

double **IViewDataTransformation P1C(IViewData, data)
{
  if (data == NULL) return(NULL);
  else return(data->transformation);
}

VOID IViewDataApplyTransformation P3C(IViewData, data, double **, a, int *, inbasis)
{
  static int temp_size;
  static double *temp;
  double **b;
  int i, j, k, vars = IViewDataNumVariables(data);

  if (data == NULL) return;
  
  if (data->transformation == NULL) IViewDataSetIdentityTransformation(data);
  data->transformed = TRUE;
  b = data->transformation;
  
  if (temp_size < vars) {
    StFree(temp);
    temp = NULL;
  }
  if (temp == NULL) {
    temp_size = vars;
    temp = (double *) StCalloc(sizeof(double), temp_size);
  }

  for (j = 0; j < vars; j++) {
    for (i = 0; i < vars; i++) 
      if (inbasis[i]){
        temp[i] = 0.0;
        for (k = 0; k < vars; k++)
          if (inbasis[k] && a[i][k] != 0.0 && b[k][j] != 0) 
            temp[i] += a[i][k] * b[k][j];
      }
    for (i = 0; i < vars; i++)
      if (inbasis[i]) b[i][j] = temp[i];
  }

  IViewBasicPointsApplyTransformation(IViewDataPoints(data), a, inbasis);
  IViewBasicPointsApplyTransformation(IViewDataLines(data), a, inbasis);
#ifdef USESTRINGS
  IViewBasicPointsApplyTransformation(IViewDataStrings(data), a, inbasis);
#endif /* USESTRINGS */
}

int IViewDataIsTransformed P1C(IViewData, data)
{
  return (data != NULL && data->transformed);
}

/**************************************************************************/
/**                                                                      **/
/**                          Point Data Functions                        **/
/**                                                                      **/
/**************************************************************************/

VOID IViewDataAddPoints P2C(IViewData, p, int, n)
{
  int i, fixed, old_n = IViewDataNumPoints(p);
    
  IViewAddBasicPoints(IViewDataPoints(p), n);
  n += old_n;
  p->pointInfo = StRRealloc(p->pointInfo, sizeof(struct point_info), n);
  
  for (i = old_n; i < n; i++) {
    IViewDataSetPointSymbol(p, i, 4, 5);
    IViewDataSetPointState(p, i, pointNormal);
    IViewDataSetPointColor(p, i, NOCOLOR);
  }
  fixed = CalculateLocationScale(p);
  IViewBasicPointsSetRecalculate(IViewDataPoints(p), fixed);
}

VOID IViewDataClearPoints P1C(IViewData, p)
{
  PointInfo *pointInfo;
  int i, n = IViewDataNumPoints(p);
   
  for (i = 0; i < n; i++) {
    pointInfo = (PointInfo *) StRPtr(p->pointInfo);
    if (pointInfo[i].label != NULL) StFree(pointInfo[i].label);
  }
  StRFree(p->pointInfo);
  p->pointInfo = NULL;
  IViewClearBasicPoints(IViewDataPoints(p));
}

int IViewDataNumPoints P1C(IViewData, p)
{
  return(IViewBasicPointsNumPoints(IViewDataPoints(p)));
}

VOID IViewDataSetPointValue P4C(IViewData, p, int, var, int, point, double, value)
{
  IViewBasicPointSetValue(IViewDataPoints(p), var, point, value);
}

double IViewDataPointValue P3C(IViewData, p, int, var, int, point)
{
  return(IViewBasicPointValue(IViewDataPoints(p), var, point));
}

double IViewDataPointTransformedValue P3C(IViewData, p, int, var, int, point)
{
  return(TransformedValue(IViewDataPoints(p), var, point));
}

int IViewDataPointScreenValue P3C(IViewData, p, int, var, int, point)
{
  return(IViewBasicPointScreenValue(IViewDataPoints(p), var, point));
}

VOID IViewDataGetScreenPointValues P3C(IViewData, d, int, point, int *, x)
{
  IViewBasicPointsGetScreenValues(IViewDataPoints(d), point, x);
}

VOID IViewDataSetPointMask P3C(IViewData, p, unsigned, point, int, masked)
{
  PointInfo *info;
  
  if (point >= IViewDataNumPoints(p)) return;
  
  info = (PointInfo *) StRPtr(p->pointInfo);
  info[point].masked = masked;
}

int IViewDataPointMasked P2C(IViewData, p, unsigned, point)
{
  PointInfo *info;
  
  if (point >= IViewDataNumPoints(p)) return(0);
  
  info = (PointInfo *) StRPtr(p->pointInfo);
  return((int) info[point].masked);
}

VOID IViewDataSetPointColor P3C(IViewData, p, unsigned, point, int, color)
{
  PointInfo *info;
  
  if (point >= IViewDataNumPoints(p)) return;
  
  info = (PointInfo *) StRPtr(p->pointInfo);
  info[point].color = color;
}

int IViewDataPointColor P2C(IViewData, p, unsigned, point)
{
  PointInfo *info;
  
  if (point >= IViewDataNumPoints(p)) return(0);
  
  info = (PointInfo *) StRPtr(p->pointInfo);
  return((int) info[point].color);
}

VOID IViewDataSetPointState P3C(IViewData, p, unsigned, point, int, state)
{
  PointInfo *info;
  
  if (point >= IViewDataNumPoints(p)) return;
  
  info = (PointInfo *) StRPtr(p->pointInfo);
  info[point].state = (PointState) state;
}

PointState IViewDataPointState P2C(IViewData, p, unsigned, point)
{
  PointInfo *info;
  
  if (point >= IViewDataNumPoints(p)) return((PointState) 0);
  
  info = (PointInfo *) StRPtr(p->pointInfo);
  return(info[point].state);
}

VOID IViewDataSetPointScreenState P3C(IViewData, p, unsigned, point, PointState, state)
{
  PointInfo *info;
  
  if (point >= IViewDataNumPoints(p)) return;
  
  info = (PointInfo *) StRPtr(p->pointInfo);
  info[point].screen_state = state;
}

PointState IViewDataPointScreenState P2C(IViewData, p, unsigned, point)
{
  PointInfo *info;
  
  if (point >= IViewDataNumPoints(p)) return((PointState) 0);
  
  info = (PointInfo *) StRPtr(p->pointInfo);
  return(info[point].screen_state);
}

VOID IViewDataResetScreenStates P1C(IViewData, p)
{
  int i, n = IViewDataNumPoints(p);
  PointInfo *info;
  
  if (p == NULL || p->pointInfo == NULL) return;
  
  info = (PointInfo *) StRPtr(p->pointInfo);
  for (i = 0; i < n; i++) info[i].screen_state = info[i].state;
}

VOID IViewDataSetPointMark P3C(IViewData, p, unsigned, point, int, marked)
{
  PointInfo *info;
  
  if (point >= IViewDataNumPoints(p)) return;
  
  info = (PointInfo *) StRPtr(p->pointInfo);
  info[point].marked = marked;
}

int IViewDataPointMarked P2C(IViewData, p, unsigned, point)
{
  PointInfo *info;
  
  if (point >= IViewDataNumPoints(p)) return(0);
  
  info = (PointInfo *) StRPtr(p->pointInfo);
  return((int) info[point].marked);
}

VOID IViewDataClearPointMarks P1C(IViewData, p)
{
  int i, n = IViewDataNumPoints(p);
  PointInfo *info;
  
  if (p == NULL || p->pointInfo == NULL) return;
  
  info = (PointInfo *) StRPtr(p->pointInfo);
  for (i = 0; i < n; i++) info[i].marked = FALSE;
}

VOID IViewDataSetPointLabel P3C(IViewData, p, unsigned, point, char *, s)
{
  PointInfo *info;
  
  if (point >= IViewDataNumPoints(p)) return;
  
  StRLock(p->pointInfo);
  info = (PointInfo *) StRPtr(p->pointInfo);
  
  StFree(info[point].label);
  info[point].label = NULL;
  if (s != 0 && strlen(s) != 0) {
    info[point].label = StCalloc(sizeof(char), 1 + strlen(s));
    strcpy(info[point].label, s);
  }
  StRUnlock(p->pointInfo);
}

char *IViewDataPointLabel P2C(IViewData, p, unsigned, point)
{
  PointInfo *info;
  char label[100];
  
  if (point >= IViewDataNumPoints(p)) return(NULL);
  
  info = (PointInfo *) StRPtr(p->pointInfo);
  
  /* only allocate label on demand to save time and space */
  if (info[point].label == NULL) {
    sprintf(label, "%d", point);
    IViewDataSetPointLabel(p, point, label);
  }
  return(info[point].label);
}

VOID IViewDataSetPointSymbol P4C(IViewData, p, unsigned, point, int, sym, int, hsym)
{
  PointInfo *info;
  
  if (point >= IViewDataNumPoints(p)) return;
  
  info = (PointInfo *) StRPtr(p->pointInfo);
  info[point].symbol.normal = sym;
  info[point].symbol.highlighted = hsym;
}

VOID IViewDataGetPointSymbol P4C(IViewData, p, unsigned, point, int *, sym, int *, hsym)
{
  PointInfo *info;
  
  if (point >= IViewDataNumPoints(p)) return;
  
  info = (PointInfo *) StRPtr(p->pointInfo);
  if (sym != NULL) *sym = info[point].symbol.normal;
  if (hsym != NULL) *hsym = info[point].symbol.highlighted;
}
  
/**************************************************************************/
/**                                                                      **/
/**                            Line Data Functions                       **/
/**                                                                      **/
/**************************************************************************/

int IViewDataNumLines P1C(IViewData, p)
{
  return(IViewBasicPointsNumPoints(IViewDataLines(p)));
}

VOID IViewDataAddLines P2C(IViewData, p, int, n)
{
  int i, old_n = IViewDataNumLines(p);
  if (p == NULL) return;
  
  IViewAddBasicPoints(IViewDataLines(p), n);
  n += old_n;
  p->lineInfo = StRRealloc(p->lineInfo, sizeof(struct line_info), n);
  
  for (i = old_n; i < n - 1; i++) {
    IViewDataSetNextLine(p, i, i + 1);
    IViewDataSetLineType(p, i, 0);
    IViewDataSetLineColor(p, i, NOCOLOR);
    IViewDataSetLineWidth(p, i, 1);
  }
  IViewDataSetNextLine(p, n - 1, -1);
  IViewDataSetLineType(p, n - 1, 0);  
  IViewDataSetLineColor(p, n - 1, NOCOLOR);
  IViewDataSetLineWidth(p, n - 1, 1);
}

VOID IViewDataClearLines P1C(IViewData, p)
{
  StRFree(p->lineInfo);
  p->lineInfo = NULL;
  IViewClearBasicPoints(IViewDataLines(p));
}

VOID IViewDataSetLineValue P4C(IViewData, p, int, var, int, line, double, value)
{
  IViewBasicPointSetValue(IViewDataLines(p), var, line, value);
}

double IViewDataLineValue P3C(IViewData, p, int, var, int, line)
{
  return(IViewBasicPointValue(IViewDataLines(p), var, line));
}

double IViewDataLineTransformedValue P3C(IViewData, p, int, var, int, line)
{
  return(TransformedValue(IViewDataLines(p), var, line));
}

int IViewDataLineScreenValue P3C(IViewData, p, int, var, int, line)
{
  return(IViewBasicPointScreenValue(IViewDataLines(p), var, line));
}

VOID IViewDataSetLineMask P3C(IViewData, p, unsigned, line, int, masked)
{
  LineInfo *info;
  
  if (line >= IViewDataNumLines(p)) return;
  
  info = (LineInfo *) StRPtr(p->lineInfo);
  info[line].masked = masked;
}

int IViewDataLineMasked P2C(IViewData, p, unsigned, line)
{
  LineInfo *info;
  
  if (line >= IViewDataNumLines(p)) return(0);
  
  info = (LineInfo *) StRPtr(p->lineInfo);
  return((int) info[line].masked);
}

VOID IViewDataSetLineColor P3C(IViewData, p, unsigned, line, int, color)
{
  LineInfo *info;
  
  if (line >= IViewDataNumLines(p)) return;
  
  info = (LineInfo *) StRPtr(p->lineInfo);
  info[line].color = color;
}

int IViewDataLineColor P2C(IViewData, p, unsigned, line)
{
  LineInfo *info;
  
  if (line >= IViewDataNumLines(p)) return(0);
  
  info = (LineInfo *) StRPtr(p->lineInfo);
  return((int) info[line].color);
}

VOID IViewDataSetLineWidth P3C(IViewData, p, unsigned, line, unsigned, width)
{
  LineInfo *info;
  
  if (line >= IViewDataNumLines(p)) return;
  
  info = (LineInfo *) StRPtr(p->lineInfo);
  info[line].width = width;
}

VOID IViewDataGetLineWidth P3C(IViewData, p, unsigned, line, unsigned *, width)
{
  LineInfo *info;
  
  if (line >= IViewDataNumLines(p)) return;
  
  info = (LineInfo *) StRPtr(p->lineInfo);
  if (width != 0) *width = (int) info[line].width;
}

VOID IViewDataSetNextLine P3C(IViewData, p, unsigned, line, int, next)
{
  LineInfo *info;
  
  if (line >= IViewDataNumLines(p) || next >= IViewDataNumLines(p)) return;

  info = (LineInfo *) StRPtr(p->lineInfo);
  info[line].next = next;
}

int IViewDataNextLine P2C(IViewData, p, unsigned, line)
{
  LineInfo *info;
  
  if (line >= IViewDataNumLines(p)) return(0);
  
  info = (LineInfo *) StRPtr(p->lineInfo);
  return(info[line].next);
}

VOID IViewDataSetLineType P3C(IViewData, p, unsigned, line, int, type)
{
  LineInfo *info;
  
  if (line >= IViewDataNumLines(p)) return;
  
  info = (LineInfo *) StRPtr(p->lineInfo);
  info[line].type = type;
}

int IViewDataLineType P2C(IViewData, p, unsigned, line)
{
  LineInfo *info;
  
  if (line >= IViewDataNumLines(p)) return(0);
  
  info = (LineInfo *) StRPtr(p->lineInfo);
  return(info[line].type);
}

#ifdef USESTRINGS
/**************************************************************************/
/**                                                                      **/
/**                           String Data Functions                      **/
/**                                                                      **/
/**************************************************************************/

IViewDataNumStrings(p)
	IViewData p;
{
  return(IViewBasicPointsNumPoints(IViewDataStrings(p)));
}

IViewDataAddStrings(p, n)
     IViewData p;
     int n;
{
  int i, old_n = IViewDataNumStrings(p);
  if (p == NULL) return;
  
  IViewAddBasicPoints(IViewDataStrings(p), n);
  n += old_n;
  p->stringInfo = StRRealloc(p->stringInfo, sizeof(struct string_info), n);
  
  for (i = old_n; i < n; i++) IViewDataSetStringColor(p, i, NOCOLOR);
}

IViewDataClearStrings(p)
	IViewData p;
{
  StringInfo *stringInfo;
  int i, n = IViewDataNumStrings(p);
   
  for (i = 0; i < n; i++) {
    stringInfo = (StringInfo *) StRPtr(p->stringInfo);
    if (stringInfo[i].string != NULL) StFree(stringInfo[i].string);
  }
  StRFree(p->stringInfo);
  p->stringInfo = NULL;
  IViewClearBasicPoints(IViewDataStrings(p));
}

IViewDataSetStringValue(p, var, string, value)
	IViewData p;
	int var, string;
	double value;
{
  IViewBasicPointSetValue(IViewDataStrings(p), var, string, value);
}

double IViewDataStringValue(p, var, string)
	IViewData p;
	int var, string;
{
  return(IViewBasicPointValue(IViewDataStrings(p), var, string));
}

double IViewDataStringTransformedValue(p, var, string)
	IViewData p;
	int var, string;
{
  return(TransformedValue(IViewDataStrings(p), var, string));
}

IViewDataStringScreenValue(p, var, string)
	IViewData p;
	int var, string;
{
  return(IViewBasicPointScreenValue(IViewDataStrings(p), var, string));
}

IViewDataSetStringMask(p, string, masked)
     IViewData p;
     unsigned string;
     int masked;
{
  StringInfo *info;
  
  if (string >= IViewDataNumStrings(p)) return;
  
  info = (StringInfo *) StRPtr(p->stringInfo);
  info[string].masked = masked;
}

IViewDataStringMasked(p, string)
     IViewData p;
     unsigned string;
{
  StringInfo *info;
  
  if (string >= IViewDataNumStrings(p)) return(0);
  
  info = (StringInfo *) StRPtr(p->stringInfo);
  return((int) info[string].masked);
}

IViewDataSetStringColor(p, string, color)
     IViewData p;
     unsigned string;
     int color;
{
  StringInfo *info;
  
  if (string >= IViewDataNumStrings(p)) return;
  
  info = (StringInfo *) StRPtr(p->stringInfo);
  info[string].color = color;
}

IViewDataStringColor(p, string)
     IViewData p;
     unsigned string;
{
  StringInfo *info;
  
  if (string >= IViewDataNumStrings(p)) return(0);
  
  info = (StringInfo *) StRPtr(p->stringInfo);
  return((int) info[string].color);
}

IViewDataSetStringString(p, string, s)
     IViewData p;
     unsigned string;
     char *s;
{
  StringInfo *info;
  
  if (string >= IViewDataNumStrings(p)) return;
  
  info = (StringInfo *) StRPtr(p->stringInfo);
  StRLock(p->stringInfo);
  StFree(info[string].string);
  info[string].string = NULL;
  if (s != 0 && strlen(s) > 0) {
    info[string].string = StCalloc(sizeof(char), 1 + strlen(s));
    strcpy(info[string].string, s);
  }
  StRUnlock(p->stringInfo);
}

char *IViewDataStringString(p, string)
     IViewData p;
     unsigned string;
{
  StringInfo *info;
  
  if (string >= IViewDataNumStrings(p)) return(NULL);
  
  info = (StringInfo *) StRPtr(p->stringInfo);
  return(info[string].string);
}

IViewDataSetStringModifiers(p, string, up, h, v)
     IViewData p;
     unsigned string;
     int up, h, v;
{
  StringInfo *info;
  
  if (string >= IViewDataNumStrings(p)) return;
  
  info = (StringInfo *) StRPtr(p->stringInfo);
  info[string].up = up;
  info[string].h = h;
  info[string].v = v;
}

IViewDataGetStringModifiers(p, string, up, h, v)
     IViewData p;
     unsigned string;
     int *up, *h, *v;
{
  StringInfo *info;
  
  if (string >= IViewDataNumStrings(p)) return;
  
  info = (StringInfo *) StRPtr(p->stringInfo);
  if (up != NULL) *up = info[string].up;
  if (h != NULL) *h = info[string].h;
  if (v != NULL) *v = info[string].v;
}
#endif /* USESTRINGS */

/**************************************************************************/
/**                                                                      **/
/**                          Data Drawing Functions                      **/
/**                                                                      **/
/**************************************************************************/

VOID IViewDataDrawPoints P7C(IViewData, data, IVIEW_WINDOW, w,
                             unsigned, var1, unsigned, var2,
                             unsigned, m, unsigned, n,
                             int, offset)
{
  int vars = IViewNumVariables(w);
  int right, bottom;
  int point, left, top, width, height, orig_x, orig_y;
  int showingLabels = IViewShowingLabels(w);
  int x, y, sym, hsym;
  PointState state;
  PointInfo *info;
  Fixed *screen1, *screen2;
  StGWWinInfo *gwinfo = IViewWindowWinInfo(w);
  int mode = StGWDrawMode(gwinfo);
  int draw_color = 0, use_color = StGWUseColor(gwinfo);
  
  if (n > IViewNumPoints(w)) return;
  if (var1 >= vars || var2 >= vars) return;
  if (data == NULL || data->pointInfo == NULL || data->points == NULL) return;
  if (data->points->screen_data[var1] == NULL 
      || data->points->screen_data[var2] == NULL) return;
  
  if (data->points->recalculateScreenPoints)
    RecalculateScreenPoints(data->points);
  info = (PointInfo *) StRPtr(data->pointInfo);
  screen1 = (Fixed *) StRPtr(data->points->screen_data[var1]);
  screen2 = (Fixed *) StRPtr(data->points->screen_data[var2]);

  StGrGetContentRect(gwinfo, &left, &top, &width, &height);
  StGrGetContentOrigin(gwinfo, &orig_x, &orig_y);
  right = left + width;
  bottom = top + height;

  if (use_color) draw_color = StGWDrawColor(gwinfo);
  for (point = m; point < n; point++, info++) {/*** info not right if m > 0 */
    state = info->state;
    sym = info->symbol.normal;
    hsym = info->symbol.highlighted;
    if (! info->masked && state != pointInvisible) {
#ifdef PERSPECTIVE
      x = orig_x + PerspScreenValue(data->points, var1, point);
      y = orig_y - PerspScreenValue(data->points, var2, point);
#else
      x = orig_x + FixRound(screen1[point]);
      y = orig_y - FixRound(screen2[point]);
#endif /* PERSPECTIVE */
      if (TRUE /* x >= left && x <= right && y >= top && y <= bottom */) {
        if (use_color) {
          if (info->color != NOCOLOR) StGWSetDrawColor(gwinfo, info->color);
          else StGWSetDrawColor(gwinfo, draw_color);
        }
        if (state == pointNormal) StGWDrawSymbol(gwinfo, sym, x, y);
        else {
          StGWDrawSymbol(gwinfo, hsym, x, y);
          if (showingLabels) {
            StGWSetDrawMode(gwinfo, 1);
            StGWDrawString(gwinfo, info->label, x + offset, y - offset);
            StGWSetDrawMode(gwinfo, mode);
          }
        }
      }
    }
  }
  if (use_color) StGWSetDrawColor(gwinfo, draw_color);
}

VOID IViewDataCuePoints P7C(IViewData, data, unsigned, var,
                            int, cut1, int, cut2, int, cut3,
                            unsigned, m, unsigned, n)
{
  int vars;
  int point;
  PointInfo *info;
  Fixed fcut1, fcut2, fcut3;
  Fixed *screen_z, z;
  
  if (data == NULL || data->pointInfo == NULL || data->points == NULL) return;
  if (data->points->screen_data[var] == NULL) return;
  if (n > IViewDataNumPoints(data)) return;
  vars = IViewDataNumVariables(data);
  if (var >= vars) return;
  
  if (data->points->recalculateScreenPoints)
    RecalculateScreenPoints(data->points);
  info = (PointInfo *) StRPtr(data->pointInfo);
  screen_z = (Fixed *) StRPtr(data->points->screen_data[var]);

  fcut1 = Int2Fixed(cut1);
  fcut2 = Int2Fixed(cut2);
  fcut3 = Int2Fixed(cut3);
  for (point = m; point < n; point++, info++) {
    z = screen_z[point];
    if (z < fcut1) info->symbol.normal = 0;
    else if (z < fcut2) info->symbol.normal = 1;
    else if (z < fcut3) info->symbol.normal = 2;
    else info->symbol.normal = 3;
    info->symbol.highlighted = 5;
  }
}

#ifdef PERSPECTIVE
static PerspScreenValue P3C(IViewBasicPoints, p, unsigned, var, unsigned, point)
{
  Fixed screen_x, screen_z, d = 800;

  if (p->num_variables > 2 && p->num_variables > var) {
    screen_z = FixRound(((Fixed *) StRPtr(p->screen_data[2]))[point]);
    /* could create problems if StRPtr return value is zero JKL */
    screen_x = FixRound(((Fixed *) StRPtr(p->screen_data[var]))[point]);
    if (screen_z != d) {
      screen_x = (screen_x * d) / (d - screen_z);
      return((int) screen_x);
    }
    else return(FixRound(screen_x));
  }
  else return(0);
}
#endif /* PERSPECTIVE */

VOID IViewDataDrawLines P6C(IViewData, data, IVIEW_WINDOW, w,
                            unsigned, var1, unsigned, var2,
                            unsigned, m, unsigned, n)
{
  int vars = IViewNumVariables(w);
  int i, left, top, width, height, orig_x, orig_y, use_color;
  int line_type, line_width, draw_color=0;
  int old_line_type, old_line_width, old_draw_color;
  StGWWinInfo *gwinfo;
  LineInfo *info;
  Fixed *screen1, *screen2;
  int x, y, nx, ny;
  int next;
  /*  int right, bottom;*/
  int type, color, linewidth;
  
  gwinfo = IViewWindowWinInfo(w);
  
  if (var1 >= vars || var2 >= vars) return;
  if (n > IViewNumLines(w)) return;
  
  if (data == NULL || data->lineInfo == NULL || data->lines == NULL) return;
  if (data->lines->screen_data[var1] == NULL 
      || data->lines->screen_data[var2] == NULL) return;
  
  if (data->lines->recalculateScreenPoints)
    RecalculateScreenPoints(data->lines);
  info = (LineInfo *) StRPtr(data->lineInfo);
  screen1 = (Fixed *) StRPtr(data->lines->screen_data[var1]);
  screen2 = (Fixed *) StRPtr(data->lines->screen_data[var2]);

  StGrGetContentRect(gwinfo, &left, &top, &width, &height);
  StGrGetContentOrigin(gwinfo, &orig_x, &orig_y);
  use_color = StGWUseColor(gwinfo);
  line_type = StGWLineType(gwinfo);
  StGWGetLineWidth(gwinfo, &line_width);
  if (use_color) draw_color = StGWDrawColor(gwinfo);
  linewidth = old_line_width = line_width;
  type = old_line_type = line_type;
  color = old_draw_color = draw_color;
  /* right = left + width; bottom = top + height; */
  
  for (i = m; i < n; i++) {  
    if (i >= n || info[i].masked) continue;
    x = orig_x + FixRound(screen1[i]);
    y = orig_y - FixRound(screen2[i]);
    /* if (x < left || x > right || y < top || y > bottom) continue;*/

    next = info[i].next;
    if (next >= n || next < 0 || info[next].masked) continue;
    nx = orig_x + FixRound(screen1[next]);
    ny = orig_y - FixRound(screen2[next]);
    /*  if (nx < left || nx > right || ny < top || ny > bottom) continue;*/
  
    /**** avoid drawing state changes if not needed; maybe pack values */
    if (info[i].width != linewidth) {
	  linewidth = info[i].width;
      StGWSetLineWidth(gwinfo, linewidth);
	}
    if (use_color) {
	  if (info[i].color != color) {
        color = info[i].color;
        if (color != NOCOLOR) StGWSetDrawColor(gwinfo, color);
        else StGWSetDrawColor(gwinfo, draw_color);
	  }
    }
    if (info[i].type != type) {
	  type = info[i].type;
      StGWSetLineType(gwinfo, type);
	}
	
    StGWDrawLine(gwinfo, x, y, nx, ny);
  }

  StGWSetLineType(gwinfo, old_line_type);
  StGWSetLineWidth(gwinfo, old_line_width);
  if (use_color) StGWSetDrawColor(gwinfo, old_draw_color);
}
/**** do cuing also */


syntax highlighted by Code2HTML, v. 0.9.1