/* This is -*- C -*- */
/* vim: set sw=2: */
/* $Id: guppi-curve-poly.c,v 1.1 2002/01/08 06:28:59 trow Exp $ */

/*
 * guppi-curve-poly-impl.c
 *
 * Copyright (C) 2000 EMC Capital Management, Inc.
 * Copyright (C) 2001 The Free Software Foundation
 *
 * Developed by Jon Trowbridge <trow@gnu.org>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 */

#include <config.h>
#include "guppi-curve-poly.h"

#include <math.h>
#include <gnan.h>
#include <guppi-memory.h>
#include <guppi-convenient.h>
#include <guppi-data-plug-in.h>

static GtkObjectClass *parent_class = NULL;

enum {
  ARG_0,
  ARG_POLYNOMIAL
};

static void
guppi_curve_poly_get_arg (GtkObject *obj, GtkArg *arg, guint arg_id)
{
  GuppiCurvePoly *poly = GUPPI_CURVE_POLY (obj);
  
  switch (arg_id) {

  case ARG_POLYNOMIAL:
    GTK_VALUE_POINTER (*arg) = guppi_curve_poly_get_polynomial (poly);
    break;

  default:
    break;
  };
}

static void
guppi_curve_poly_set_arg (GtkObject *obj, GtkArg *arg, guint arg_id)
{
  GuppiCurvePoly *poly = GUPPI_CURVE_POLY (obj);

  switch (arg_id) {

  case ARG_POLYNOMIAL:
    guppi_curve_poly_set_polynomial (poly, GUPPI_POLYNOMIAL (GTK_VALUE_POINTER (*arg)));
    break;

  default:
    break;
  };
}

static void
guppi_curve_poly_finalize (GtkObject *obj)
{
  GuppiCurvePoly *x = GUPPI_CURVE_POLY(obj);

  guppi_unref (x->poly);
  if (x->changed_handler)
    gtk_signal_disconnect (obj, x->changed_handler);

  if (parent_class->finalize)
    parent_class->finalize (obj);
}

/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */

static void
get (GuppiCurve *curve, double t, double *x, double *y)
{
  GuppiCurvePoly *poly = GUPPI_CURVE_POLY (curve);
  
  if (x)
    *x = t;
  if (y)
    *y = guppi_polynomial_eval (poly->poly, t);
}

static void
bbox (GuppiCurve *curve, double a, double b, 
      double *x0, double *y0, double *x1, double *y1)
{
  GuppiCurvePoly *poly = GUPPI_CURVE_POLY (curve);

  if (x0) *x0 = a;
  if (x1) *x1 = b;

  if (! (y0 || y1))
    return;

  guppi_polynomial_minmax_on_range (poly->poly, a, b, y0, y1);
}

static gboolean
clamp (GuppiCurve *curve, double *a, double *b,
       double x0, double y0, double x1, double y1)
{
  /*GuppiCurvePoly *poly = GUPPI_CURVE_POLY (curve);*/

  if (a) *a = x0;
  if (b) *b = x1;

  return TRUE;
}


static void
sample (GuppiCurve *curve, gconstpointer t_vec, gint t_stride, gsize N,
	gpointer x_vec, gint x_stride,
	gpointer y_vec, gint y_stride)
{
  GuppiCurvePoly *cp = GUPPI_CURVE_POLY (curve);
  GuppiPolynomial *poly = guppi_curve_poly_get_polynomial (cp);
  gint i;

  guppi_polynomial_sample (poly, N,
			   (const double *) t_vec, t_stride,
			   (double *) y_vec, y_stride);

  if (x_vec) {
    for (i = 0; i < N; ++i) {
      *(double *) x_vec = *(double *) t_vec;
      t_vec = (gconstpointer) (((gchar *) t_vec) + t_stride);
      x_vec =      (gpointer) (((gchar *) x_vec) + x_stride);
    }
  }
}

static void
sample_uniformly (GuppiCurve *curve,
		  double t0, double t1, gsize N,
		  double *x_vec, gint x_stride,
		  double *y_vec, gint y_stride)
{
  GuppiCurvePoly *cp = GUPPI_CURVE_POLY (curve);
  GuppiPolynomial *poly = guppi_curve_poly_get_polynomial (cp);

  guppi_polynomial_sample_uniformly (poly, t0, t1, N,
				     x_vec, x_stride,
				     y_vec, y_stride);
  
}

static ArtVpath *
approx_to_path (GuppiCurve *curve, double t0, double t1,
		double x_error, double y_error,
		double x0, double y0, double x1, double y1,
		double scale_x, double scale_y)
{
  GuppiCurvePoly *cp = GUPPI_CURVE_POLY (cp);
  GuppiPolynomial *poly = guppi_curve_poly_get_polynomial (cp);

  return guppi_polynomial_approximate_path (poly, t0, t1, y0, y1,
					    x_error, y_error, 0,
					    scale_x, scale_y);
}

/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */

#define add_arg(str, t, symb) \
gtk_object_add_arg_type ("GuppiCurvePoly::" str, t, GTK_ARG_READWRITE, symb)

static void
guppi_curve_poly_class_init (GuppiCurvePolyClass *klass)
{
  GtkObjectClass *object_class = (GtkObjectClass *)klass;
  GuppiCurveClass *curve_class = GUPPI_CURVE_CLASS (klass);

  parent_class = gtk_type_class (GUPPI_TYPE_CURVE);

  //  curve_class->bounds = bounds;
  curve_class->get = get;
  curve_class->bbox = bbox;
  curve_class->clamp = clamp;
  curve_class->sample = sample;
  curve_class->sample_uniformly = sample_uniformly;
  curve_class->approx_to_path = approx_to_path;

  object_class->get_arg = guppi_curve_poly_get_arg;
  object_class->set_arg = guppi_curve_poly_set_arg;
  object_class->finalize = guppi_curve_poly_finalize;

  add_arg ("polynomial", GTK_TYPE_POINTER, ARG_POLYNOMIAL);
}

static void
guppi_curve_poly_init (GuppiCurvePoly *obj)
{
  obj->min = -G_INFINITY;
  obj->max = G_INFINITY;
}

GtkType
guppi_curve_poly_get_type (void)
{
  static GtkType guppi_curve_poly_type = 0;
  if (!guppi_curve_poly_type) {
    static const GtkTypeInfo guppi_curve_poly_info = {
      "GuppiCurvePoly",
      sizeof (GuppiCurvePoly),
      sizeof (GuppiCurvePolyClass),
      (GtkClassInitFunc)guppi_curve_poly_class_init,
      (GtkObjectInitFunc)guppi_curve_poly_init,
      NULL, NULL, (GtkClassInitFunc)NULL
    };
    guppi_curve_poly_type = gtk_type_unique (GUPPI_TYPE_CURVE, &guppi_curve_poly_info);
  }
  return guppi_curve_poly_type;
}

/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */

GuppiCurve *
guppi_curve_poly_new (void)
{
  return GUPPI_CURVE (guppi_type_new (guppi_curve_poly_get_type ()));
}

GuppiPolynomial *
guppi_curve_poly_get_polynomial (GuppiCurvePoly *curve)
{
  g_return_val_if_fail (GUPPI_IS_CURVE_POLY (curve), NULL);
  return curve->poly;
}

void
guppi_curve_poly_set_polynomial (GuppiCurvePoly *curve, GuppiPolynomial *p)
{
  g_return_if_fail (GUPPI_IS_CURVE_POLY (curve));
  g_return_if_fail (p && GUPPI_IS_POLYNOMIAL (p));

  if (p != curve->poly) {
    
    if (curve->changed_handler)
      gtk_signal_disconnect (GTK_OBJECT (curve->poly), curve->changed_handler);

    guppi_refcounting_assign (curve->poly, p);

    curve->changed_handler = gtk_signal_connect_object (GTK_OBJECT (p),
							"changed",
							GTK_SIGNAL_FUNC (guppi_data_changed),
							GTK_OBJECT (curve));

    guppi_data_changed (GUPPI_DATA (curve));
  }
}

GuppiPolynomial *
guppi_curve_get_polynomial (GuppiData *data)
{
  g_return_val_if_fail (data && GUPPI_IS_DATA (data), NULL);

  if (!GUPPI_IS_CURVE_POLY (data))
    return NULL;

  return guppi_curve_poly_get_polynomial (GUPPI_CURVE_POLY (data));
}


syntax highlighted by Code2HTML, v. 0.9.1