/* This is -*- C -*- */
/* vim: set sw=2: */
/* $Id: guppi-curve-interpolate.c,v 1.1 2002/01/08 06:28:59 trow Exp $ */
/*
* guppi-curve-interpolate-impl.c
*
* 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-interpolate.h"
#include <math.h>
#include <guppi-memory.h>
#include <guppi-data-plug-in.h>
#include <guppi-seq-scalar.h>
static GtkObjectClass *parent_class = NULL;
enum {
ARG_0,
ARG_X_DATA,
ARG_Y_DATA
};
static gboolean allowed_data_type (GuppiSeq *);
static void interpolate_set_x_data (GuppiCurveInterpolate *, GuppiSeq *);
static void interpolate_set_y_data (GuppiCurveInterpolate *, GuppiSeq *);
static void
guppi_curve_interpolate_get_arg (GtkObject *obj, GtkArg *arg, guint arg_id)
{
GuppiCurveInterpolate *interp = GUPPI_CURVE_INTERPOLATE (obj);
switch (arg_id) {
case ARG_X_DATA:
GTK_VALUE_POINTER (*arg) = interp->x_data;
break;
case ARG_Y_DATA:
GTK_VALUE_POINTER (*arg) = interp->y_data;
break;
default:
break;
};
}
static void
guppi_curve_interpolate_set_arg (GtkObject *obj, GtkArg *arg, guint arg_id)
{
GuppiCurveInterpolate *interp = GUPPI_CURVE_INTERPOLATE (obj);
switch (arg_id) {
case ARG_X_DATA:
interpolate_set_x_data (interp, GUPPI_SEQ (GTK_VALUE_POINTER (*arg)));
break;
case ARG_Y_DATA:
interpolate_set_y_data (interp, GUPPI_SEQ (GTK_VALUE_POINTER (*arg)));
break;
default:
break;
};
}
static void
guppi_curve_interpolate_finalize (GtkObject *obj)
{
GuppiCurveInterpolate *interp = GUPPI_CURVE_INTERPOLATE(obj);
guppi_unref (interp->x_data);
guppi_unref (interp->y_data);
guppi_finalized (obj);
if (parent_class->finalize)
parent_class->finalize (obj);
}
/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
static void
bounds (GuppiCurve *curve, double *a, double *b)
{
GuppiCurveInterpolate *interp = GUPPI_CURVE_INTERPOLATE (curve);
gint min_bound, max_bound;
if (interp->x_data && interp->y_data) {
guppi_seq_common_bounds (interp->x_data, interp->y_data, &min_bound, &max_bound);
} else {
min_bound = max_bound = 0;
}
if (a) *a = min_bound;
if (b) *b = max_bound;
}
static double
lookup_value (GuppiSeq *seq, gint i)
{
if (GUPPI_IS_SEQ_SCALAR (seq)) {
return guppi_seq_scalar_get ((GuppiSeqScalar *) seq, i);
}
return 0;
}
static void
get (GuppiCurve *curve, double t, double *x, double *y)
{
GuppiCurveInterpolate *interp = GUPPI_CURVE_INTERPOLATE (curve);
double xx, yy;
if (interp->x_data && interp->y_data) {
gint t_int = (gint)floor (t);
double t_frac = t - t_int;
double x0, y0, x1, y1;
if (t_frac < 1e-8) {
xx = lookup_value (interp->x_data, t_int);
yy = lookup_value (interp->y_data, t_int);
} else {
x0 = lookup_value (interp->x_data, t_int);
x1 = lookup_value (interp->x_data, t_int+1);
y0 = lookup_value (interp->y_data, t_int);
y1 = lookup_value (interp->y_data, t_int+1);
xx = (1-t_frac) * x0 + t_frac * x1;
yy = (1-t_frac) * y0 + t_frac * y1;
}
} else {
xx = 0;
yy = 0;
}
if (x) *x = xx;
if (y) *y = yy;
}
static void
bbox (GuppiCurve *curve, double t0, double t1,
double *x0, double *y0, double *x1, double *y1)
{
GuppiCurveInterpolate *interp = GUPPI_CURVE_INTERPOLATE (curve);
double mx, Mx, my, My, x, y;
gint i, i0, i1;
i0 = (gint) ceil (t0);
i1 = (gint) floor (t1);
if (interp->x_data && interp->y_data) {
get (curve, t0, &mx, &my);
Mx = mx, My = my;
for (i = i0; i <= i1; ++i) {
x = lookup_value (interp->x_data, i);
if (x < mx) mx = x;
if (x > Mx) Mx = x;
y = lookup_value (interp->y_data, i);
if (y < my) my = y;
if (y > My) My = y;
}
get (curve, t1, &x, &y);
if (x < mx) mx = x;
if (x > Mx) Mx = x;
if (y < my) my = y;
if (y > My) My = y;
} else {
mx = my = Mx = My = 0;
}
if (x0) *x0 = mx;
if (x1) *x1 = Mx;
if (y0) *y0 = my;
if (y1) *y1 = My;
}
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)
{
GuppiCurveInterpolate *interp = GUPPI_CURVE_INTERPOLATE (curve);
gint i, i0, i1, N, j = 0;
double x, y, xp, yp;
gboolean ok;
ArtVpath *path = NULL;
if (interp->x_data == NULL || interp->y_data == NULL)
return NULL;
ok = TRUE;
i0 = (gint) ceil (t0);
i1 = (gint) floor (t1);
N = i1 - i0 + 4;
path = g_new0 (ArtVpath, N);
/* First point */
path[j].code = ART_MOVETO;
get (curve, t0, &path[j].x, &path[j].y);
++j;
for (i = i0; i <= i1; ++i) {
x = lookup_value (interp->x_data, i);
y = lookup_value (interp->y_data, i);
if (j > 0) {
xp = path[j-1].x;
yp = path[j-1].y;
if (ok && fabs (scale_x * (x - xp)) < 0.5 && fabs (scale_y * (y - yp)) < 0.5)
ok = FALSE;
/* Need to do window queries */
/* Need to do colinearity checks */
}
if (ok) {
path[j].code = ART_LINETO;
path[j].x = x;
path[j].y = y;
++j;
}
}
path[j].code = ART_END;
return path;
}
/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
static void
guppi_curve_interpolate_class_init (GuppiCurveInterpolateClass *klass)
{
GtkObjectClass *object_class = (GtkObjectClass *)klass;
GuppiCurveClass *curve_class = GUPPI_CURVE_CLASS (klass);
parent_class = gtk_type_class (GUPPI_TYPE_CURVE);
object_class->get_arg = guppi_curve_interpolate_get_arg;
object_class->set_arg = guppi_curve_interpolate_set_arg;
object_class->finalize = guppi_curve_interpolate_finalize;
curve_class->bounds = bounds;
curve_class->get = get;
curve_class->bbox = bbox;
curve_class->approx_to_path = approx_to_path;
}
static void
guppi_curve_interpolate_init (GuppiCurveInterpolate *obj)
{
}
GtkType
guppi_curve_interpolate_get_type (void)
{
static GtkType guppi_curve_interpolate_type = 0;
if (!guppi_curve_interpolate_type) {
static const GtkTypeInfo guppi_curve_interpolate_info = {
"GuppiCurveInterpolate",
sizeof (GuppiCurveInterpolate),
sizeof (GuppiCurveInterpolateClass),
(GtkClassInitFunc)guppi_curve_interpolate_class_init,
(GtkObjectInitFunc)guppi_curve_interpolate_init,
NULL, NULL, (GtkClassInitFunc)NULL
};
guppi_curve_interpolate_type = gtk_type_unique (GUPPI_TYPE_CURVE, &guppi_curve_interpolate_info);
}
return guppi_curve_interpolate_type;
}
/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
static gboolean
allowed_data_type (GuppiSeq *seq)
{
if (seq == NULL)
return TRUE;
if (GUPPI_IS_SEQ_SCALAR (seq))
return TRUE;
return FALSE;
}
static void
interpolate_set_x_data (GuppiCurveInterpolate *interp, GuppiSeq *data)
{
g_return_if_fail (GUPPI_IS_CURVE_INTERPOLATE (interp));
g_return_if_fail (allowed_data_type (data));
if (interp->x_data != data) {
if (interp->changed_x_handler)
gtk_signal_disconnect (GTK_OBJECT (interp->x_data), interp->changed_x_handler);
guppi_refcounting_assign (interp->x_data, data);
if (data)
interp->changed_x_handler = gtk_signal_connect_object (GTK_OBJECT (data),
"changed",
GTK_SIGNAL_FUNC (guppi_data_changed),
GTK_OBJECT (interp));
guppi_data_changed (GUPPI_DATA (interp));
}
}
static void
interpolate_set_y_data (GuppiCurveInterpolate *interp, GuppiSeq *data)
{
g_return_if_fail (GUPPI_IS_CURVE_INTERPOLATE (interp));
g_return_if_fail (allowed_data_type (data));
if (interp->y_data != data) {
if (interp->changed_y_handler)
gtk_signal_disconnect (GTK_OBJECT (interp->y_data), interp->changed_y_handler);
guppi_refcounting_assign (interp->y_data, data);
if (data)
interp->changed_y_handler = gtk_signal_connect_object (GTK_OBJECT (data),
"changed",
GTK_SIGNAL_FUNC (guppi_data_changed),
GTK_OBJECT (interp));
guppi_data_changed (GUPPI_DATA (interp));
}
}
syntax highlighted by Code2HTML, v. 0.9.1