diff options
Diffstat (limited to 'overlay/chart.c')
-rw-r--r-- | overlay/chart.c | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/overlay/chart.c b/overlay/chart.c new file mode 100644 index 00000000..2a33d612 --- /dev/null +++ b/overlay/chart.c @@ -0,0 +1,236 @@ +/* + * Copyright © 2013 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + */ + +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <cairo.h> + +#include <stdio.h> + +#include "chart.h" + +int chart_init(struct chart *chart, const char *name, int num_samples) +{ + memset(chart, 0, sizeof(*chart)); + chart->name = name; + chart->samples = malloc(sizeof(*chart->samples)*num_samples); + if (chart->samples == NULL) + return ENOMEM; + + chart->num_samples = num_samples; + chart->range_automatic = 1; + chart->stroke_width = 2; + chart->smooth = CHART_CURVE; + return 0; +} + +void chart_set_mode(struct chart *chart, enum chart_mode mode) +{ + chart->mode = mode; +} + +void chart_set_smooth(struct chart *chart, enum chart_smooth smooth) +{ + chart->smooth = smooth; +} + +void chart_set_stroke_width(struct chart *chart, float width) +{ + chart->stroke_width = width; +} + +void chart_set_stroke_rgba(struct chart *chart, float red, float green, float blue, float alpha) +{ + chart->stroke_rgb[0] = red; + chart->stroke_rgb[1] = green; + chart->stroke_rgb[2] = blue; + chart->stroke_rgb[3] = alpha; +} + +void chart_set_fill_rgba(struct chart *chart, float red, float green, float blue, float alpha) +{ + chart->fill_rgb[0] = red; + chart->fill_rgb[1] = green; + chart->fill_rgb[2] = blue; + chart->fill_rgb[3] = alpha; +} + +void chart_set_position(struct chart *chart, int x, int y) +{ + chart->x = x; + chart->y = y; +} + +void chart_set_size(struct chart *chart, int w, int h) +{ + chart->w = w; + chart->h = h; +} + +void chart_set_range(struct chart *chart, double min, double max) +{ + chart->range[0] = min; + chart->range[1] = max; + chart->range_automatic = 0; +} + +void chart_get_range(struct chart *chart, double *range) +{ + int n, max = chart->current_sample; + if (max > chart->num_samples) + max = chart->num_samples; + for (n = 0; n < max; n++) { + if (chart->samples[n] < range[0]) + range[0] = chart->samples[n]; + else if (chart->samples[n] > range[1]) + range[1] = chart->samples[n]; + } +} + +void chart_add_sample(struct chart *chart, double value) +{ + int pos; + + if (chart->num_samples == 0) + return; + + pos = chart->current_sample++ % chart->num_samples; + chart->samples[pos] = value; +} + +static void chart_update_range(struct chart *chart) +{ + int n, max = chart->current_sample; + if (max > chart->num_samples) + max = chart->num_samples; + chart->range[0] = chart->range[1] = chart->samples[0]; + for (n = 1; n < max; n++) { + if (chart->samples[n] < chart->range[0]) + chart->range[0] = chart->samples[n]; + else if (chart->samples[n] > chart->range[1]) + chart->range[1] = chart->samples[n]; + } + if (strcmp(chart->name, "power") == 0) + printf ("chart_update_range [%f, %f]\n", chart->range[0], chart->range[1]); +} + +static double value_at(struct chart *chart, int n) +{ + if (n < chart->current_sample - chart->num_samples) + n = chart->current_sample; + else if (n >= chart->current_sample) + n = chart->current_sample - 1; + + return chart->samples[n % chart->num_samples]; +} + +static double gradient_at(struct chart *chart, int n) +{ + double y0, y1; + + y0 = value_at(chart, n-1); + y1 = value_at(chart, n+1); + + return (y1 - y0) / 2.; +} + +void chart_draw(struct chart *chart, cairo_t *cr) +{ + int i, n, max, x; + + if (chart->current_sample == 0) + return; + + if (chart->range_automatic) + chart_update_range(chart); + + if (chart->range[1] <= chart->range[0]) + return; + + cairo_save(cr); + + cairo_translate(cr, chart->x, chart->y + chart->h); + cairo_scale(cr, + chart->w / (double)(chart->num_samples-1), + -chart->h / (chart->range[1] - chart->range[0])); + + x = 0; + max = chart->current_sample; + if (max >= chart->num_samples) { + max = chart->num_samples; + i = chart->current_sample - max; + } else { + i = 0; + x = chart->num_samples - max; + } + cairo_translate(cr, x, -chart->range[0]); + + cairo_new_path(cr); + if (chart->mode != CHART_STROKE) + cairo_move_to(cr, 0, 0); + for (n = 0; n < max; n++) { + switch (chart->smooth) { + case CHART_LINE: + cairo_line_to(cr, + n, value_at(chart, i + n)); + break; + case CHART_CURVE: + cairo_curve_to(cr, + n-2/3., value_at(chart, i + n -1) + gradient_at(chart, i + n - 1)/3., + n-1/3., value_at(chart, i + n) - gradient_at(chart, i + n)/3., + n, value_at(chart, i + n)); + break; + } + } + if (chart->mode != CHART_STROKE) + cairo_line_to(cr, n-1, 0); + + cairo_identity_matrix(cr); + cairo_set_line_width(cr, chart->stroke_width); + switch (chart->mode) { + case CHART_STROKE: + cairo_set_source_rgba(cr, chart->stroke_rgb[0], chart->stroke_rgb[1], chart->stroke_rgb[2], chart->stroke_rgb[3]); + cairo_stroke(cr); + break; + case CHART_FILL: + cairo_set_source_rgba(cr, chart->fill_rgb[0], chart->fill_rgb[1], chart->fill_rgb[2], chart->fill_rgb[3]); + cairo_fill(cr); + break; + case CHART_FILL_STROKE: + cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE); + cairo_set_source_rgba(cr, chart->fill_rgb[0], chart->fill_rgb[1], chart->fill_rgb[2], chart->fill_rgb[3]); + cairo_fill_preserve(cr); + cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT); + cairo_set_source_rgba(cr, chart->stroke_rgb[0], chart->stroke_rgb[1], chart->stroke_rgb[2], chart->stroke_rgb[3]); + cairo_stroke(cr); + break; + } + cairo_restore(cr); +} + +void chart_fini(struct chart *chart) +{ + free(chart->samples); +} |