/* 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 <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-date-series-core.h"
#include <libgnome/gnome-defs.h>
#include <libgnome/gnome-config.h>
#include <libgnome/gnome-i18n.h>
#include <math.h>
#include <gnan.h>
#include <guppi-convenient.h>
#include <guppi-memory.h>
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 ()));
}
syntax highlighted by Code2HTML, v. 0.9.1