/* 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 * * 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 #include "guppi-curve-interpolate.h" #include #include #include #include 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)); } }