示例#1
0
int
stp_curve_set_subrange(stp_curve_t *curve, const stp_curve_t *range,
		       size_t start)
{
  double blo, bhi;
  double rlo, rhi;
  const double *data;
  size_t count;
  CHECK_CURVE(curve);
  if (start + stp_curve_count_points(range) > stp_curve_count_points(curve))
    return 0;
  if (curve->piecewise)
    return 0;
  stp_sequence_get_bounds(curve->seq, &blo, &bhi);
  stp_sequence_get_range(curve->seq, &rlo, &rhi);
  if (rlo < blo || rhi > bhi)
    return 0;
  stp_sequence_get_data(range->seq, &count, &data);
  curve->recompute_interval = 1;
  curve->gamma = 0.0;
  invalidate_auxiliary_data(curve);
  stp_sequence_set_subrange(curve->seq, start, stp_curve_count_points(range),
			    data);
  return 1;
}
示例#2
0
int
stp_dither_matrix_validate_array(const stp_array_t *array)
{
  double low, high;
  const stp_sequence_t *seq = stp_array_get_sequence(array);
  stp_sequence_get_bounds(seq, &low, &high);
  if (low < 0 || high > 65535)
    return 0;
  return 1;
}
示例#3
0
static inline double
interpolate_point_internal(const stp_curve_t *curve, double where)
{
  int integer = where;
  double frac = where - (double) integer;
  double bhi, blo;

  if (frac == 0.0)
    {
      double val;
      if ((stp_sequence_get_point(curve->seq, integer, &val)) == 0)
	return HUGE_VAL; /* Infinity */
      return val;
    }
  if (curve->recompute_interval)
    compute_intervals((stpi_cast_safe(curve)));
  if (curve->curve_type == STP_CURVE_TYPE_LINEAR)
    {
      double val;
      if ((stp_sequence_get_point(curve->seq, integer, &val)) == 0)
	return HUGE_VAL; /* Infinity */
      return val + frac * curve->interval[integer];
    }
  else
    {
      size_t point_count;
      double ival, ip1val;
      double retval;
      int i = integer;
      int ip1 = integer + 1;

      point_count = get_point_count(curve);

      if (ip1 >= point_count)
	ip1 -= point_count;

      if ((stp_sequence_get_point(curve->seq, i, &ival)) == 0 ||
	  (stp_sequence_get_point(curve->seq, ip1, &ip1val)) == 0)
	return HUGE_VAL; /* Infinity */

      retval = do_interpolate_spline(ival, ip1val, frac, curve->interval[i],
				     curve->interval[ip1], 1.0);

      stp_sequence_get_bounds(curve->seq, &blo, &bhi);
      if (retval > bhi)
	retval = bhi;
      if (retval < blo)
	retval = blo;
      return retval;
    }
}
示例#4
0
static int
stpi_curve_check_parameters(stp_curve_t *curve, size_t points)
{
  double blo, bhi;
  if (curve->gamma && curve->wrap_mode)
    {
      stp_deprintf(STP_DBG_CURVE_ERRORS,
		   "curve sets both gamma and wrap_mode\n");
      return 0;
    }
  stp_sequence_get_bounds(curve->seq, &blo, &bhi);
  if (blo > bhi)
    {
      stp_deprintf(STP_DBG_CURVE_ERRORS,
		   "curve low bound is greater than high bound\n");
      return 0;
    }
  return 1;
}
示例#5
0
static inline double
interpolate_gamma_internal(const stp_curve_t *curve, double where)
{
  double fgamma = curve->gamma;
  double blo, bhi;
  size_t real_point_count;

  real_point_count = get_real_point_count(curve);;

  if (real_point_count)
    where /= (real_point_count - 1);
  if (fgamma < 0)
    {
      where = 1.0 - where;
      fgamma = -fgamma;
    }
  stp_sequence_get_bounds(curve->seq, &blo, &bhi);
  stp_deprintf(STP_DBG_CURVE,
	       "interpolate_gamma %f %f %f %f %f\n", where, fgamma,
	       blo, bhi, pow(where, fgamma));
  return blo + (bhi - blo) * pow(where, fgamma);
}
示例#6
0
int
stp_curve_set_data(stp_curve_t *curve, size_t count, const double *data)
{
  size_t i;
  size_t real_count = count;
  double low, high;
  CHECK_CURVE(curve);
  if (count < 2)
    return 0;
  if (curve->wrap_mode == STP_CURVE_WRAP_AROUND)
    real_count++;
  if (real_count > curve_point_limit)
    return 0;

  /* Validate the data before we commit to it. */
  stp_sequence_get_bounds(curve->seq, &low, &high);
  for (i = 0; i < count; i++)
    if (! isfinite(data[i]) || data[i] < low || data[i] > high)
      {
	stp_deprintf(STP_DBG_CURVE_ERRORS,
		     "stp_curve_set_data: datum out of bounds: "
		     "%g (require %g <= x <= %g), n = %ld\n",
		     data[i], low, high, (long)i);
	return 0;
      }
  /* Allocate sequence; also accounts for WRAP_MODE */
  stpi_curve_set_points(curve, count);
  curve->gamma = 0.0;
  stp_sequence_set_subrange(curve->seq, 0, count, data);

  if (curve->wrap_mode == STP_CURVE_WRAP_AROUND)
    stp_sequence_set_point(curve->seq, count, data[0]);
  curve->recompute_interval = 1;
  curve->piecewise = 0;

  return 1;
}
示例#7
0
int
stp_curve_rescale(stp_curve_t *curve, double scale,
		  stp_curve_compose_t mode, stp_curve_bounds_t bounds_mode)
{
  int i;
  double nblo;
  double nbhi;
  size_t count;

  CHECK_CURVE(curve);

  stp_sequence_get_bounds(curve->seq, &nblo, &nbhi);
  if (bounds_mode == STP_CURVE_BOUNDS_RESCALE)
    {
      switch (mode)
	{
	case STP_CURVE_COMPOSE_ADD:
	  nblo += scale;
	  nbhi += scale;
	  break;
	case STP_CURVE_COMPOSE_MULTIPLY:
	  if (scale < 0)
	    {
	      double tmp = nblo * scale;
	      nblo = nbhi * scale;
	      nbhi = tmp;
	    }
	  else
	    {
	      nblo *= scale;
	      nbhi *= scale;
	    }
	  break;
	case STP_CURVE_COMPOSE_EXPONENTIATE:
	  if (scale == 0.0)
	    return 0;
	  if (nblo < 0)
	    return 0;
	  nblo = pow(nblo, scale);
	  nbhi = pow(nbhi, scale);
	  break;
	default:
	  return 0;
	}
    }

  if (! isfinite(nbhi) || ! isfinite(nblo))
    return 0;

  count = get_point_count(curve);
  if (count)
    {
      double *tmp;
      size_t scount;
      int stride = 1;
      int offset = 0;
      const double *data;
      if (curve->piecewise)
	{
	  stride = 2;
	  offset = 1;
	}
      stp_sequence_get_data(curve->seq, &scount, &data);
      tmp = stp_malloc(sizeof(double) * scount);
      memcpy(tmp, data, scount * sizeof(double));
      for (i = offset; i < scount; i += stride)
	{
	  switch (mode)
	    {
	    case STP_CURVE_COMPOSE_ADD:
	      tmp[i] = tmp[i] + scale;
	      break;
	    case STP_CURVE_COMPOSE_MULTIPLY:
	      tmp[i] = tmp[i] * scale;
	      break;
	    case STP_CURVE_COMPOSE_EXPONENTIATE:
	      tmp[i] = pow(tmp[i], scale);
	      break;
	    }
	  if (tmp[i] > nbhi || tmp[i] < nblo)
	    {
	      if (bounds_mode == STP_CURVE_BOUNDS_ERROR)
		{
		  stp_free(tmp);
		  return(0);
		}
	      else if (tmp[i] > nbhi)
		tmp[i] = nbhi;
	      else
		tmp[i] = nblo;
	    }
	}
      stp_sequence_set_bounds(curve->seq, nblo, nbhi);
      curve->gamma = 0.0;
      stpi_curve_set_points(curve, count);
      stp_sequence_set_subrange(curve->seq, 0, scount, tmp);
      stp_free(tmp);
      curve->recompute_interval = 1;
      invalidate_auxiliary_data(curve);
    }
  return 1;
}
示例#8
0
int
stp_curve_set_data_points(stp_curve_t *curve, size_t count,
			  const stp_curve_point_t *data)
{
  size_t i;
  size_t real_count = count;
  double low, high;
  double last_x = -1;
  CHECK_CURVE(curve);
  if (count < 2)
    {
      stp_deprintf(STP_DBG_CURVE_ERRORS,
		   "stp_curve_set_data_points: too few points %ld\n", (long)count);
      return 0;
    }
  if (curve->wrap_mode == STP_CURVE_WRAP_AROUND)
    real_count++;
  if (real_count > curve_point_limit)
    {
      stp_deprintf(STP_DBG_CURVE_ERRORS,
		   "stp_curve_set_data_points: too many points %ld\n",
		   (long)real_count);
      return 0;
    }

  /* Validate the data before we commit to it. */
  stp_sequence_get_bounds(curve->seq, &low, &high);
  for (i = 0; i < count; i++)
    {
      if (! isfinite(data[i].y) || data[i].y < low || data[i].y > high)
	{
	  stp_deprintf(STP_DBG_CURVE_ERRORS,
		       "stp_curve_set_data_points: datum out of bounds: "
		       "%g (require %g <= x <= %g), n = %ld\n",
		       data[i].y, low, high, (long)i);
	  return 0;
	}
      if (i == 0 && data[i].x != 0.0)
	{
	  stp_deprintf(STP_DBG_CURVE_ERRORS,
		       "stp_curve_set_data_points: first point must have x=0\n");
	  return 0;
	}
      if (curve->wrap_mode == STP_CURVE_WRAP_NONE && i == count - 1 &&
	  data[i].x != 1.0)
	{
	  stp_deprintf(STP_DBG_CURVE_ERRORS,
		       "stp_curve_set_data_points: last point must have x=1\n");
	  return 0;
	}
      if (curve->wrap_mode == STP_CURVE_WRAP_AROUND &&
	  data[i].x >= 1.0 - .000001)
	{
	  stp_deprintf(STP_DBG_CURVE_ERRORS,
		       "stp_curve_set_data_points: horizontal value must "
		       "not exceed .99999\n");
	  return 0;
	}	  
      if (data[i].x < 0 || data[i].x > 1)
	{
	  stp_deprintf(STP_DBG_CURVE_ERRORS,
		       "stp_curve_set_data_points: horizontal position out of bounds: "
		       "%g, n = %ld\n",
		       data[i].x, (long)i);
	  return 0;
	}
      if (data[i].x - .000001 < last_x)
	{
	  stp_deprintf(STP_DBG_CURVE_ERRORS,
		       "stp_curve_set_data_points: horizontal position must "
		       "exceed previous position by .000001: %g, %g, n = %ld\n",
		       data[i].x, last_x, (long)i);
	  return 0;
	}
      last_x = data[i].x;
    }
  /* Allocate sequence; also accounts for WRAP_MODE */
  curve->piecewise = 1;
  stpi_curve_set_points(curve, count);
  curve->gamma = 0.0;
  stp_sequence_set_subrange(curve->seq, 0, count * 2, (const double *) data);

  if (curve->wrap_mode == STP_CURVE_WRAP_AROUND)
    {
      stp_sequence_set_point(curve->seq, count * 2, data[0].x);
      stp_sequence_set_point(curve->seq, count * 2 + 1, data[0].y);
    }
  curve->recompute_interval = 1;

  return 1;
}
示例#9
0
void
stp_curve_get_bounds(const stp_curve_t *curve, double *low, double *high)
{
  CHECK_CURVE(curve);
  stp_sequence_get_bounds(curve->seq, low, high);
}
示例#10
0
stp_curve_t *
stp_curve_create_from_xmltree(stp_mxml_node_t *curve)  /* The curve node */
{
  const char *stmp;                       /* Temporary string */
  stp_mxml_node_t *child;                 /* Child sequence node */
  stp_curve_t *ret = NULL;                /* Curve to return */
  stp_curve_type_t curve_type;            /* Type of curve */
  stp_curve_wrap_mode_t wrap_mode;        /* Curve wrap mode */
  double fgamma;                          /* Gamma value */
  stp_sequence_t *seq = NULL;             /* Sequence data */
  double low, high;                       /* Sequence bounds */
  int piecewise = 0;

  stp_xml_init();
  /* Get curve type */
  stmp = stp_mxmlElementGetAttr(curve, "type");
  if (stmp)
    {
      if (!strcmp(stmp, "linear"))
	  curve_type = STP_CURVE_TYPE_LINEAR;
      else if (!strcmp(stmp, "spline"))
	  curve_type = STP_CURVE_TYPE_SPLINE;
      else
	{
	  stp_deprintf(STP_DBG_CURVE_ERRORS,
		       "stp_curve_create_from_xmltree: %s: \"type\" invalid\n", stmp);
	  goto error;
	}
    }
  else
    {
      stp_deprintf(STP_DBG_CURVE_ERRORS,
		   "stp_curve_create_from_xmltree: \"type\" missing\n");
      goto error;
    }
  /* Get curve wrap mode */
  stmp = stp_mxmlElementGetAttr(curve, "wrap");
  if (stmp)
    {
      if (!strcmp(stmp, "nowrap"))
	wrap_mode = STP_CURVE_WRAP_NONE;
      else if (!strcmp(stmp, "wrap"))
	{
	  wrap_mode = STP_CURVE_WRAP_AROUND;
	}
      else
	{
	  stp_deprintf(STP_DBG_CURVE_ERRORS,
		       "stp_curve_create_from_xmltree: %s: \"wrap\" invalid\n", stmp);
	  goto error;
	}
    }
  else
    {
      stp_deprintf(STP_DBG_CURVE_ERRORS,
		   "stp_curve_create_from_xmltree: \"wrap\" missing\n");
      goto error;
    }
  /* Get curve gamma */
  stmp = stp_mxmlElementGetAttr(curve, "gamma");
  if (stmp)
    {
      fgamma = stp_xmlstrtod(stmp);
    }
  else
    {
      stp_deprintf(STP_DBG_CURVE_ERRORS,
		   "stp_curve_create_from_xmltree: \"gamma\" missing\n");
      goto error;
    }
  /* If gamma is set, wrap_mode must be STP_CURVE_WRAP_NONE */
  if (fgamma && wrap_mode != STP_CURVE_WRAP_NONE)
    {
      stp_deprintf(STP_DBG_CURVE_ERRORS, "stp_curve_create_from_xmltree: "
		   "gamma set and \"wrap\" is not STP_CURVE_WRAP_NONE\n");
      goto error;
    }
  stmp = stp_mxmlElementGetAttr(curve, "piecewise");
  if (stmp && strcmp(stmp, "true") == 0)
    piecewise = 1;

  /* Set up the curve */
  ret = stp_curve_create(wrap_mode);
  stp_curve_set_interpolation_type(ret, curve_type);

  child = stp_mxmlFindElement(curve, curve, "sequence", NULL, NULL, STP_MXML_DESCEND);
  if (child)
    seq = stp_sequence_create_from_xmltree(child);

  if (seq == NULL)
    {
      stp_deprintf(STP_DBG_CURVE_ERRORS,
		   "stp_curve_create_from_xmltree: sequence read failed\n");
      goto error;
    }

  /* Set curve bounds */
  stp_sequence_get_bounds(seq, &low, &high);
  stp_curve_set_bounds(ret, low, high);

  if (fgamma)
    stp_curve_set_gamma(ret, fgamma);
  else /* Not a gamma curve, so set points */
    {
      size_t seq_count;
      const double* data;

      stp_sequence_get_data(seq, &seq_count, &data);
      if (piecewise)
	{
	  if ((seq_count % 2) != 0)
	    {
	      stp_deprintf(STP_DBG_CURVE_ERRORS,
			   "stp_curve_create_from_xmltree: invalid data count %ld\n",
			   (long)seq_count);
	      goto error;
	    }
	  if (stp_curve_set_data_points(ret, seq_count / 2,
					(const stp_curve_point_t *) data) == 0)
	    {
	      stp_deprintf(STP_DBG_CURVE_ERRORS,
			   "stp_curve_create_from_xmltree: failed to set curve data points\n");
	      goto error;
	    }
	}
      else
	{
	  if (stp_curve_set_data(ret, seq_count, data) == 0)
	    {
	      stp_deprintf(STP_DBG_CURVE_ERRORS,
			   "stp_curve_create_from_xmltree: failed to set curve data\n");
	      goto error;
	    }
	}
    }

  if (seq)
    {
      stp_sequence_destroy(seq);
      seq = NULL;
    }

    /* Validate curve */
  if (stpi_curve_check_parameters(ret, stp_curve_count_points(ret)) == 0)
    {
      stp_deprintf(STP_DBG_CURVE_ERRORS,
		   "stp_curve_create_from_xmltree: parameter check failed\n");
      goto error;
    }

  stp_xml_exit();

  return ret;

 error:
  stp_deprintf(STP_DBG_CURVE_ERRORS,
	       "stp_curve_create_from_xmltree: error during curve read\n");
  if (ret)
    stp_curve_destroy(ret);
  stp_xml_exit();
  return NULL;
}
示例#11
0
int
stp_curve_resample(stp_curve_t *curve, size_t points)
{
  size_t limit = points;
  size_t old;
  size_t i;
  double *new_vec;

  CHECK_CURVE(curve);

  if (points == get_point_count(curve) && curve->seq && !(curve->piecewise))
    return 1;

  if (points < 2)
    return 1;

  if (curve->wrap_mode == STP_CURVE_WRAP_AROUND)
    limit++;
  if (limit > curve_point_limit)
    return 0;
  old = get_real_point_count(curve);
  if (old)
    old--;
  if (!old)
    old = 1;

  new_vec = stp_malloc(sizeof(double) * limit);

  /*
   * Be very careful how we calculate the location along the scale!
   * If we're not careful how we do it, we might get a small roundoff
   * error
   */
  if (curve->piecewise)
    {
      double blo, bhi;
      int curpos = 0;
      stp_sequence_get_bounds(curve->seq, &blo, &bhi);
      if (curve->recompute_interval)
	compute_intervals(curve);
      for (i = 0; i < old; i++)
	{
	  double low;
	  double high;
	  double low_y;
	  double high_y;
	  double x_delta;
	  if (!stp_sequence_get_point(curve->seq, i * 2, &low))
	    {
	      stp_free(new_vec);
	      return 0;
	    }
	  if (i == old - 1)
	    high = 1.0;
	  else if (!stp_sequence_get_point(curve->seq, ((i + 1) * 2), &high))
	    {
	      stp_free(new_vec);
	      return 0;
	    }
	  if (!stp_sequence_get_point(curve->seq, (i * 2) + 1, &low_y))
	    {
	      stp_free(new_vec);
	      return 0;
	    }
	  if (!stp_sequence_get_point(curve->seq, ((i + 1) * 2) + 1, &high_y))
	    {
	      stp_free(new_vec);
	      return 0;
	    }
	  stp_deprintf(STP_DBG_CURVE,
		       "Filling slots at %ld %d: %f %f  %f %f  %ld\n",
		       (long)i,curpos, high, low, high_y, low_y, (long)limit);
	  x_delta = high - low;
	  high *= (limit - 1);
	  low *= (limit - 1);
	  while (curpos <= high)
	    {
	      double frac = (curpos - low) / (high - low);
	      if (curve->curve_type == STP_CURVE_TYPE_LINEAR)
		new_vec[curpos] = low_y + frac * (high_y - low_y);
	      else
		new_vec[curpos] =
		  do_interpolate_spline(low_y, high_y, frac,
					curve->interval[i],
					curve->interval[i + 1],
					x_delta);
	      if (new_vec[curpos] < blo)
		new_vec[curpos] = blo;
	      if (new_vec[curpos] > bhi)
		new_vec[curpos] = bhi;
	      stp_deprintf(STP_DBG_CURVE,
			   "  Filling slot %d %f %f\n",
			   curpos, frac, new_vec[curpos]);
	      curpos++;
	    }
	}
      curve->piecewise = 0;
    }
  else
    {
      for (i = 0; i < limit; i++)
	if (curve->gamma)
	  new_vec[i] =
	    interpolate_gamma_internal(curve, ((double) i * (double) old /
					       (double) (limit - 1)));
	else
	  new_vec[i] =
	    interpolate_point_internal(curve, ((double) i * (double) old /
					       (double) (limit - 1)));
    }
  stpi_curve_set_points(curve, points);
  stp_sequence_set_subrange(curve->seq, 0, limit, new_vec);
  curve->recompute_interval = 1;
  stp_free(new_vec);
  return 1;
}