/* This is -*- C -*- */ /* vim: set sw=2: */ /* * core.c * * Copyright (C) 2000 EMC Capital Management, Inc. * 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-date-series-core.h" #include #include #include #include #include #include #include static GtkObjectClass *parent_class = NULL; static void guppi_date_series_core_finalize (GtkObject *obj) { GuppiDateSeriesCore *core = GUPPI_DATE_SERIES_CORE (obj); guppi_unref0 (core->garray); if (parent_class->finalize) parent_class->finalize (obj); } /* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */ static void ensure_contains (GuppiDateSeriesCore *core, const GDate *dt) { double *data; gint i; if (core->size == 0) { guppi_garray_set_size (core->garray, 186); core->size = 1; core->start_date = *dt; core->end_date = *dt; data = (double *)guppi_garray_data (core->garray); data[0] = G_NAN; return; } i = (gint)g_date_julian ((GDate *) dt) - (gint)g_date_julian (&core->start_date); if (0 <= i && i < core->size) return; if (i < 0) { gint new_size, j; new_size = core->size - i; if (guppi_garray_size (core->garray) < new_size) guppi_garray_set_size (core->garray, new_size); data = (double *)guppi_garray_data (core->garray); for (j = core->size-1; j >= 0; --j) data[j-i] = data[j]; for (j = 0; j<-i; ++j) data[j] = G_NAN; core->size = new_size; core->start_date = *dt; return; } if (i >= core->size) { gint new_size, j; new_size = i+1; if (guppi_garray_size (core->garray) < new_size) guppi_garray_set_size (core->garray, new_size); data = (double *)guppi_garray_data (core->garray); for (j = core->size; j < new_size; ++j) data[j] = G_NAN; core->size = new_size; core->end_date = *dt; return; } g_assert_not_reached (); } static GuppiData * v_data_copy (GuppiData *d) { g_assert_not_reached (); return NULL; } static gint v_data_get_size_in_bytes (GuppiData *d) { return -1; } static void v_di_bounds (GuppiDateIndexed *di, GDate *start, GDate *end) { GuppiDateSeriesCore *core = GUPPI_DATE_SERIES_CORE (di); if (start) *start = core->start_date; if (end) *end = core->end_date; } static gboolean v_di_valid (GuppiDateIndexed *di, const GDate *dt) { GuppiDateSeriesCore *core = GUPPI_DATE_SERIES_CORE (di); gint i; double *data; data = (double *)guppi_garray_data (core->garray); i = (gint)g_date_julian ((GDate *)dt) - (gint)g_date_julian(&core->start_date); return !g_isnan (data[i]); } static gboolean v_di_step (GuppiDateIndexed *di, const GDate *dt, gint delta, GDate *modified) { GuppiDateSeriesCore *core = GUPPI_DATE_SERIES_CORE (di); gint i, N; double *data; data = (double *)guppi_garray_data (core->garray); i = (gint)g_date_julian ((GDate *)dt) - (gint)g_date_julian(&core->start_date); N = (gint)g_date_julian (&core->end_date) - (gint)g_date_julian(&core->start_date); while (delta && 0 <= i && i <= N) { if (!g_isnan (data[i])) { if (delta > 0) --delta; else ++delta; } i += (delta > 0 ? 1 : -1); } return delta == 0; } static gint v_di_size (GuppiDateIndexed *di) { GuppiDateSeriesCore *core = GUPPI_DATE_SERIES_CORE (di); gint i, N, count; double *data; data = (double *)guppi_garray_data (core->garray); N = (gint)g_date_julian (&core->end_date) - (gint)g_date_julian(&core->start_date); count = 0; for (i=0; i<=N; ++i) if (!g_isnan (data[i])) ++count; return count; } static void v_di_bounds_hint (GuppiDateIndexed *di, const GDate *start, const GDate *end) { GuppiDateSeriesCore *core = GUPPI_DATE_SERIES_CORE (di); ensure_contains (core, (GDate *)start); ensure_contains (core, (GDate *)end); } static double v_ds_get (GuppiDateSeries *ser, const GDate *dt) { GuppiDateSeriesCore *core = GUPPI_DATE_SERIES_CORE (ser); double *data; gint i; data = (double *)guppi_garray_data (core->garray); i = (gint)g_date_julian ((GDate *) dt) - (gint)g_date_julian (&core->start_date); return data[i]; } static void v_ds_set (GuppiDateSeries *ser, const GDate *dt, double x) { GuppiDateSeriesCore *core = GUPPI_DATE_SERIES_CORE (ser); double *data; gint i; ensure_contains (core, dt); data = (double *)guppi_garray_data (core->garray); i = (gint)g_date_julian ((GDate *) dt) - (gint)g_date_julian (&core->start_date); data[i] = x; } static void v_ds_unset (GuppiDateSeries *ser, const GDate *dt) { GuppiDateSeriesCore *core = GUPPI_DATE_SERIES_CORE (ser); double *data; gint i; data = (double *)guppi_garray_data (core->garray); i = (gint)g_date_julian ((GDate *) dt) - (gint)g_date_julian (&core->start_date); if (0 <= i && i < core->size) data[i] = G_NAN; } static gboolean v_ds_get_many (GuppiDateSeries *ser, const GDate *dt, gint count, double *buf, gint *retval) { GuppiDateSeriesCore *core = GUPPI_DATE_SERIES_CORE (ser); double *data; gint i, j; data = (double *)guppi_garray_data (core->garray); i = (gint)g_date_julian ((GDate *) dt) - (gint)g_date_julian (&core->start_date); j = 0; while (count && 0 <= i && i < core->size) { if (!g_isnan (data[i])) { buf[j] = data[i]; ++j; if (count > 0) --count; else ++count; } if (count > 0) ++i; else --i; } if (retval) *retval = j; return TRUE; } static gboolean v_ds_get_range (GuppiDateSeries *ser, const GDate *sd, const GDate *ed, double *timecode, double *buf, gint bufsize, gint *retval) { GuppiDateSeriesCore *core = GUPPI_DATE_SERIES_CORE (ser); double *data; gint i, N, j, jul; data = (double *)guppi_garray_data (core->garray); jul = (gint)g_date_julian (&core->start_date); i = (gint)g_date_julian ((GDate *) sd) - jul; N = (gint)g_date_julian ((GDate *) ed) - jul; j = 0; while (j < bufsize && 0 <= i && i <= N) { if (!g_isnan (data[i])) { if (timecode) timecode[j] = jul + i; if (buf) buf[j] = data[i]; ++j; } ++i; } if (retval) *retval = j; return TRUE; } static gboolean v_ds_get_bounds (GuppiDateSeries *ser, const GDate *sd, const GDate *ed, double *min, double *max, gboolean *retval) { GuppiDateSeriesCore *core = GUPPI_DATE_SERIES_CORE (ser); double *data; gint i, N; double m = 0, M = 0; gboolean first = TRUE; data = (double *)guppi_garray_data (core->garray); i = (gint)g_date_julian ((GDate *) sd) - (gint)g_date_julian (&core->start_date); N = (gint)g_date_julian ((GDate *) ed) - (gint)g_date_julian (&core->start_date); for (i=0; i<=N; ++i) { if (!g_isnan (data[i])) { if (first) { m = M = data[i]; first = FALSE; } else { double x = data[i]; if (x < m) m = x; if (x > M) M = x; } } } if (min) *min = m; if (max) *max = M; if (retval) *retval = !first; return TRUE; } /* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */ static void guppi_date_series_core_class_init (GuppiDateSeriesCoreClass *klass) { double d; GtkObjectClass* object_class = (GtkObjectClass *)klass; GuppiDataClass *data_class = GUPPI_DATA_CLASS (klass); GuppiDateIndexedClass *di_class = GUPPI_DATE_INDEXED_CLASS (klass); GuppiDateSeriesClass *ds_class = GUPPI_DATE_SERIES_CLASS (klass); parent_class = gtk_type_class (GUPPI_TYPE_DATE_SERIES); object_class->finalize = guppi_date_series_core_finalize; data_class->copy = v_data_copy; data_class->get_size_in_bytes = v_data_get_size_in_bytes; data_class->is_leaf_type = TRUE; di_class->bounds = v_di_bounds; di_class->valid = v_di_valid; di_class->step = v_di_step; di_class->size = v_di_size; di_class->bounds_hint = v_di_bounds_hint; ds_class->get = v_ds_get; ds_class->set = v_ds_set; ds_class->unset = v_ds_unset; ds_class->get_many = v_ds_get_many; ds_class->get_range = v_ds_get_range; ds_class->get_bounds = v_ds_get_bounds; d = G_NAN; g_assert (g_isnan (d)); } static void guppi_date_series_core_init (GuppiDateSeriesCore *obj) { g_date_clear (&obj->start_date, 1); g_date_clear (&obj->end_date, 1); obj->size = 0; obj->garray = guppi_garray_new (sizeof (double)); } GtkType guppi_date_series_core_get_type (void) { static GtkType guppi_date_series_core_type = 0; if (!guppi_date_series_core_type) { static const GtkTypeInfo guppi_date_series_core_info = { "GuppiDateSeriesCore", sizeof (GuppiDateSeriesCore), sizeof (GuppiDateSeriesCoreClass), (GtkClassInitFunc)guppi_date_series_core_class_init, (GtkObjectInitFunc)guppi_date_series_core_init, NULL, NULL, (GtkClassInitFunc)NULL }; guppi_date_series_core_type = gtk_type_unique (GUPPI_TYPE_DATE_SERIES, &guppi_date_series_core_info); } return guppi_date_series_core_type; } GuppiDateSeries * guppi_date_series_core_new (void) { return GUPPI_DATE_SERIES (guppi_type_new (guppi_date_series_core_get_type ())); }