1*d83cc019SAndroid Build Coastguard Worker /*
2*d83cc019SAndroid Build Coastguard Worker * Copyright © 2013 Intel Corporation
3*d83cc019SAndroid Build Coastguard Worker *
4*d83cc019SAndroid Build Coastguard Worker * Permission is hereby granted, free of charge, to any person obtaining a
5*d83cc019SAndroid Build Coastguard Worker * copy of this software and associated documentation files (the "Software"),
6*d83cc019SAndroid Build Coastguard Worker * to deal in the Software without restriction, including without limitation
7*d83cc019SAndroid Build Coastguard Worker * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*d83cc019SAndroid Build Coastguard Worker * and/or sell copies of the Software, and to permit persons to whom the
9*d83cc019SAndroid Build Coastguard Worker * Software is furnished to do so, subject to the following conditions:
10*d83cc019SAndroid Build Coastguard Worker *
11*d83cc019SAndroid Build Coastguard Worker * The above copyright notice and this permission notice (including the next
12*d83cc019SAndroid Build Coastguard Worker * paragraph) shall be included in all copies or substantial portions of the
13*d83cc019SAndroid Build Coastguard Worker * Software.
14*d83cc019SAndroid Build Coastguard Worker *
15*d83cc019SAndroid Build Coastguard Worker * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*d83cc019SAndroid Build Coastguard Worker * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*d83cc019SAndroid Build Coastguard Worker * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18*d83cc019SAndroid Build Coastguard Worker * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*d83cc019SAndroid Build Coastguard Worker * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20*d83cc019SAndroid Build Coastguard Worker * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21*d83cc019SAndroid Build Coastguard Worker * IN THE SOFTWARE.
22*d83cc019SAndroid Build Coastguard Worker *
23*d83cc019SAndroid Build Coastguard Worker */
24*d83cc019SAndroid Build Coastguard Worker
25*d83cc019SAndroid Build Coastguard Worker #include <stdlib.h>
26*d83cc019SAndroid Build Coastguard Worker #include <string.h>
27*d83cc019SAndroid Build Coastguard Worker #include <errno.h>
28*d83cc019SAndroid Build Coastguard Worker #include <cairo.h>
29*d83cc019SAndroid Build Coastguard Worker
30*d83cc019SAndroid Build Coastguard Worker #include <stdio.h>
31*d83cc019SAndroid Build Coastguard Worker
32*d83cc019SAndroid Build Coastguard Worker #include "chart.h"
33*d83cc019SAndroid Build Coastguard Worker
chart_init(struct chart * chart,const char * name,int num_samples)34*d83cc019SAndroid Build Coastguard Worker int chart_init(struct chart *chart, const char *name, int num_samples)
35*d83cc019SAndroid Build Coastguard Worker {
36*d83cc019SAndroid Build Coastguard Worker memset(chart, 0, sizeof(*chart));
37*d83cc019SAndroid Build Coastguard Worker chart->name = name;
38*d83cc019SAndroid Build Coastguard Worker chart->samples = malloc(sizeof(*chart->samples)*num_samples);
39*d83cc019SAndroid Build Coastguard Worker if (chart->samples == NULL)
40*d83cc019SAndroid Build Coastguard Worker return ENOMEM;
41*d83cc019SAndroid Build Coastguard Worker
42*d83cc019SAndroid Build Coastguard Worker chart->num_samples = num_samples;
43*d83cc019SAndroid Build Coastguard Worker chart->range_automatic = 1;
44*d83cc019SAndroid Build Coastguard Worker chart->stroke_width = 2;
45*d83cc019SAndroid Build Coastguard Worker chart->smooth = CHART_CURVE;
46*d83cc019SAndroid Build Coastguard Worker return 0;
47*d83cc019SAndroid Build Coastguard Worker }
48*d83cc019SAndroid Build Coastguard Worker
chart_set_mode(struct chart * chart,enum chart_mode mode)49*d83cc019SAndroid Build Coastguard Worker void chart_set_mode(struct chart *chart, enum chart_mode mode)
50*d83cc019SAndroid Build Coastguard Worker {
51*d83cc019SAndroid Build Coastguard Worker chart->mode = mode;
52*d83cc019SAndroid Build Coastguard Worker }
53*d83cc019SAndroid Build Coastguard Worker
chart_set_smooth(struct chart * chart,enum chart_smooth smooth)54*d83cc019SAndroid Build Coastguard Worker void chart_set_smooth(struct chart *chart, enum chart_smooth smooth)
55*d83cc019SAndroid Build Coastguard Worker {
56*d83cc019SAndroid Build Coastguard Worker chart->smooth = smooth;
57*d83cc019SAndroid Build Coastguard Worker }
58*d83cc019SAndroid Build Coastguard Worker
chart_set_stroke_width(struct chart * chart,float width)59*d83cc019SAndroid Build Coastguard Worker void chart_set_stroke_width(struct chart *chart, float width)
60*d83cc019SAndroid Build Coastguard Worker {
61*d83cc019SAndroid Build Coastguard Worker chart->stroke_width = width;
62*d83cc019SAndroid Build Coastguard Worker }
63*d83cc019SAndroid Build Coastguard Worker
chart_set_stroke_rgba(struct chart * chart,float red,float green,float blue,float alpha)64*d83cc019SAndroid Build Coastguard Worker void chart_set_stroke_rgba(struct chart *chart, float red, float green, float blue, float alpha)
65*d83cc019SAndroid Build Coastguard Worker {
66*d83cc019SAndroid Build Coastguard Worker chart->stroke_rgb[0] = red;
67*d83cc019SAndroid Build Coastguard Worker chart->stroke_rgb[1] = green;
68*d83cc019SAndroid Build Coastguard Worker chart->stroke_rgb[2] = blue;
69*d83cc019SAndroid Build Coastguard Worker chart->stroke_rgb[3] = alpha;
70*d83cc019SAndroid Build Coastguard Worker }
71*d83cc019SAndroid Build Coastguard Worker
chart_set_fill_rgba(struct chart * chart,float red,float green,float blue,float alpha)72*d83cc019SAndroid Build Coastguard Worker void chart_set_fill_rgba(struct chart *chart, float red, float green, float blue, float alpha)
73*d83cc019SAndroid Build Coastguard Worker {
74*d83cc019SAndroid Build Coastguard Worker chart->fill_rgb[0] = red;
75*d83cc019SAndroid Build Coastguard Worker chart->fill_rgb[1] = green;
76*d83cc019SAndroid Build Coastguard Worker chart->fill_rgb[2] = blue;
77*d83cc019SAndroid Build Coastguard Worker chart->fill_rgb[3] = alpha;
78*d83cc019SAndroid Build Coastguard Worker }
79*d83cc019SAndroid Build Coastguard Worker
chart_set_position(struct chart * chart,int x,int y)80*d83cc019SAndroid Build Coastguard Worker void chart_set_position(struct chart *chart, int x, int y)
81*d83cc019SAndroid Build Coastguard Worker {
82*d83cc019SAndroid Build Coastguard Worker chart->x = x;
83*d83cc019SAndroid Build Coastguard Worker chart->y = y;
84*d83cc019SAndroid Build Coastguard Worker }
85*d83cc019SAndroid Build Coastguard Worker
chart_set_size(struct chart * chart,int w,int h)86*d83cc019SAndroid Build Coastguard Worker void chart_set_size(struct chart *chart, int w, int h)
87*d83cc019SAndroid Build Coastguard Worker {
88*d83cc019SAndroid Build Coastguard Worker chart->w = w;
89*d83cc019SAndroid Build Coastguard Worker chart->h = h;
90*d83cc019SAndroid Build Coastguard Worker }
91*d83cc019SAndroid Build Coastguard Worker
chart_set_range(struct chart * chart,double min,double max)92*d83cc019SAndroid Build Coastguard Worker void chart_set_range(struct chart *chart, double min, double max)
93*d83cc019SAndroid Build Coastguard Worker {
94*d83cc019SAndroid Build Coastguard Worker chart->range[0] = min;
95*d83cc019SAndroid Build Coastguard Worker chart->range[1] = max;
96*d83cc019SAndroid Build Coastguard Worker chart->range_automatic = 0;
97*d83cc019SAndroid Build Coastguard Worker }
98*d83cc019SAndroid Build Coastguard Worker
chart_get_range(struct chart * chart,double * range)99*d83cc019SAndroid Build Coastguard Worker void chart_get_range(struct chart *chart, double *range)
100*d83cc019SAndroid Build Coastguard Worker {
101*d83cc019SAndroid Build Coastguard Worker int n, max = chart->current_sample;
102*d83cc019SAndroid Build Coastguard Worker if (max > chart->num_samples)
103*d83cc019SAndroid Build Coastguard Worker max = chart->num_samples;
104*d83cc019SAndroid Build Coastguard Worker for (n = 0; n < max; n++) {
105*d83cc019SAndroid Build Coastguard Worker if (chart->samples[n] < range[0])
106*d83cc019SAndroid Build Coastguard Worker range[0] = chart->samples[n];
107*d83cc019SAndroid Build Coastguard Worker else if (chart->samples[n] > range[1])
108*d83cc019SAndroid Build Coastguard Worker range[1] = chart->samples[n];
109*d83cc019SAndroid Build Coastguard Worker }
110*d83cc019SAndroid Build Coastguard Worker }
111*d83cc019SAndroid Build Coastguard Worker
chart_add_sample(struct chart * chart,double value)112*d83cc019SAndroid Build Coastguard Worker void chart_add_sample(struct chart *chart, double value)
113*d83cc019SAndroid Build Coastguard Worker {
114*d83cc019SAndroid Build Coastguard Worker int pos;
115*d83cc019SAndroid Build Coastguard Worker
116*d83cc019SAndroid Build Coastguard Worker if (chart->num_samples == 0)
117*d83cc019SAndroid Build Coastguard Worker return;
118*d83cc019SAndroid Build Coastguard Worker
119*d83cc019SAndroid Build Coastguard Worker pos = chart->current_sample++ % chart->num_samples;
120*d83cc019SAndroid Build Coastguard Worker chart->samples[pos] = value;
121*d83cc019SAndroid Build Coastguard Worker }
122*d83cc019SAndroid Build Coastguard Worker
chart_update_range(struct chart * chart)123*d83cc019SAndroid Build Coastguard Worker static void chart_update_range(struct chart *chart)
124*d83cc019SAndroid Build Coastguard Worker {
125*d83cc019SAndroid Build Coastguard Worker int n, max = chart->current_sample;
126*d83cc019SAndroid Build Coastguard Worker if (max > chart->num_samples)
127*d83cc019SAndroid Build Coastguard Worker max = chart->num_samples;
128*d83cc019SAndroid Build Coastguard Worker chart->range[0] = chart->range[1] = chart->samples[0];
129*d83cc019SAndroid Build Coastguard Worker for (n = 1; n < max; n++) {
130*d83cc019SAndroid Build Coastguard Worker if (chart->samples[n] < chart->range[0])
131*d83cc019SAndroid Build Coastguard Worker chart->range[0] = chart->samples[n];
132*d83cc019SAndroid Build Coastguard Worker else if (chart->samples[n] > chart->range[1])
133*d83cc019SAndroid Build Coastguard Worker chart->range[1] = chart->samples[n];
134*d83cc019SAndroid Build Coastguard Worker }
135*d83cc019SAndroid Build Coastguard Worker if (strcmp(chart->name, "power") == 0)
136*d83cc019SAndroid Build Coastguard Worker printf ("chart_update_range [%f, %f]\n", chart->range[0], chart->range[1]);
137*d83cc019SAndroid Build Coastguard Worker }
138*d83cc019SAndroid Build Coastguard Worker
value_at(struct chart * chart,int n)139*d83cc019SAndroid Build Coastguard Worker static double value_at(struct chart *chart, int n)
140*d83cc019SAndroid Build Coastguard Worker {
141*d83cc019SAndroid Build Coastguard Worker if (n < chart->current_sample - chart->num_samples)
142*d83cc019SAndroid Build Coastguard Worker n = chart->current_sample;
143*d83cc019SAndroid Build Coastguard Worker else if (n >= chart->current_sample)
144*d83cc019SAndroid Build Coastguard Worker n = chart->current_sample - 1;
145*d83cc019SAndroid Build Coastguard Worker
146*d83cc019SAndroid Build Coastguard Worker n %= chart->num_samples;
147*d83cc019SAndroid Build Coastguard Worker if (n < 0)
148*d83cc019SAndroid Build Coastguard Worker n += chart->num_samples;
149*d83cc019SAndroid Build Coastguard Worker
150*d83cc019SAndroid Build Coastguard Worker return chart->samples[n];
151*d83cc019SAndroid Build Coastguard Worker }
152*d83cc019SAndroid Build Coastguard Worker
gradient_at(struct chart * chart,int n)153*d83cc019SAndroid Build Coastguard Worker static double gradient_at(struct chart *chart, int n)
154*d83cc019SAndroid Build Coastguard Worker {
155*d83cc019SAndroid Build Coastguard Worker double y0, y1;
156*d83cc019SAndroid Build Coastguard Worker
157*d83cc019SAndroid Build Coastguard Worker y0 = value_at(chart, n-1);
158*d83cc019SAndroid Build Coastguard Worker y1 = value_at(chart, n+1);
159*d83cc019SAndroid Build Coastguard Worker
160*d83cc019SAndroid Build Coastguard Worker return (y1 - y0) / 2.;
161*d83cc019SAndroid Build Coastguard Worker }
162*d83cc019SAndroid Build Coastguard Worker
chart_draw(struct chart * chart,cairo_t * cr)163*d83cc019SAndroid Build Coastguard Worker void chart_draw(struct chart *chart, cairo_t *cr)
164*d83cc019SAndroid Build Coastguard Worker {
165*d83cc019SAndroid Build Coastguard Worker int i, n, max, x;
166*d83cc019SAndroid Build Coastguard Worker
167*d83cc019SAndroid Build Coastguard Worker if (chart->current_sample == 0)
168*d83cc019SAndroid Build Coastguard Worker return;
169*d83cc019SAndroid Build Coastguard Worker
170*d83cc019SAndroid Build Coastguard Worker if (chart->range_automatic)
171*d83cc019SAndroid Build Coastguard Worker chart_update_range(chart);
172*d83cc019SAndroid Build Coastguard Worker
173*d83cc019SAndroid Build Coastguard Worker if (chart->range[1] <= chart->range[0])
174*d83cc019SAndroid Build Coastguard Worker return;
175*d83cc019SAndroid Build Coastguard Worker
176*d83cc019SAndroid Build Coastguard Worker cairo_save(cr);
177*d83cc019SAndroid Build Coastguard Worker
178*d83cc019SAndroid Build Coastguard Worker cairo_translate(cr, chart->x, chart->y + chart->h);
179*d83cc019SAndroid Build Coastguard Worker cairo_scale(cr,
180*d83cc019SAndroid Build Coastguard Worker chart->w / (double)(chart->num_samples-1),
181*d83cc019SAndroid Build Coastguard Worker -chart->h / (chart->range[1] - chart->range[0]));
182*d83cc019SAndroid Build Coastguard Worker
183*d83cc019SAndroid Build Coastguard Worker x = 0;
184*d83cc019SAndroid Build Coastguard Worker max = chart->current_sample;
185*d83cc019SAndroid Build Coastguard Worker if (max >= chart->num_samples) {
186*d83cc019SAndroid Build Coastguard Worker max = chart->num_samples;
187*d83cc019SAndroid Build Coastguard Worker i = chart->current_sample - max;
188*d83cc019SAndroid Build Coastguard Worker } else {
189*d83cc019SAndroid Build Coastguard Worker i = 0;
190*d83cc019SAndroid Build Coastguard Worker x = chart->num_samples - max;
191*d83cc019SAndroid Build Coastguard Worker }
192*d83cc019SAndroid Build Coastguard Worker cairo_translate(cr, x, -chart->range[0]);
193*d83cc019SAndroid Build Coastguard Worker
194*d83cc019SAndroid Build Coastguard Worker cairo_new_path(cr);
195*d83cc019SAndroid Build Coastguard Worker if (chart->mode != CHART_STROKE)
196*d83cc019SAndroid Build Coastguard Worker cairo_move_to(cr, 0, 0);
197*d83cc019SAndroid Build Coastguard Worker for (n = 0; n < max; n++) {
198*d83cc019SAndroid Build Coastguard Worker switch (chart->smooth) {
199*d83cc019SAndroid Build Coastguard Worker case CHART_LINE:
200*d83cc019SAndroid Build Coastguard Worker cairo_line_to(cr,
201*d83cc019SAndroid Build Coastguard Worker n, value_at(chart, i + n));
202*d83cc019SAndroid Build Coastguard Worker break;
203*d83cc019SAndroid Build Coastguard Worker case CHART_CURVE:
204*d83cc019SAndroid Build Coastguard Worker cairo_curve_to(cr,
205*d83cc019SAndroid Build Coastguard Worker n-2/3., value_at(chart, i + n -1) + gradient_at(chart, i + n - 1)/3.,
206*d83cc019SAndroid Build Coastguard Worker n-1/3., value_at(chart, i + n) - gradient_at(chart, i + n)/3.,
207*d83cc019SAndroid Build Coastguard Worker n, value_at(chart, i + n));
208*d83cc019SAndroid Build Coastguard Worker break;
209*d83cc019SAndroid Build Coastguard Worker }
210*d83cc019SAndroid Build Coastguard Worker }
211*d83cc019SAndroid Build Coastguard Worker if (chart->mode != CHART_STROKE)
212*d83cc019SAndroid Build Coastguard Worker cairo_line_to(cr, n-1, 0);
213*d83cc019SAndroid Build Coastguard Worker
214*d83cc019SAndroid Build Coastguard Worker cairo_identity_matrix(cr);
215*d83cc019SAndroid Build Coastguard Worker cairo_set_line_width(cr, chart->stroke_width);
216*d83cc019SAndroid Build Coastguard Worker switch (chart->mode) {
217*d83cc019SAndroid Build Coastguard Worker case CHART_STROKE:
218*d83cc019SAndroid Build Coastguard Worker cairo_set_source_rgba(cr, chart->stroke_rgb[0], chart->stroke_rgb[1], chart->stroke_rgb[2], chart->stroke_rgb[3]);
219*d83cc019SAndroid Build Coastguard Worker cairo_stroke(cr);
220*d83cc019SAndroid Build Coastguard Worker break;
221*d83cc019SAndroid Build Coastguard Worker case CHART_FILL:
222*d83cc019SAndroid Build Coastguard Worker cairo_set_source_rgba(cr, chart->fill_rgb[0], chart->fill_rgb[1], chart->fill_rgb[2], chart->fill_rgb[3]);
223*d83cc019SAndroid Build Coastguard Worker cairo_fill(cr);
224*d83cc019SAndroid Build Coastguard Worker break;
225*d83cc019SAndroid Build Coastguard Worker case CHART_FILL_STROKE:
226*d83cc019SAndroid Build Coastguard Worker cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
227*d83cc019SAndroid Build Coastguard Worker cairo_set_source_rgba(cr, chart->fill_rgb[0], chart->fill_rgb[1], chart->fill_rgb[2], chart->fill_rgb[3]);
228*d83cc019SAndroid Build Coastguard Worker cairo_fill_preserve(cr);
229*d83cc019SAndroid Build Coastguard Worker cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT);
230*d83cc019SAndroid Build Coastguard Worker cairo_set_source_rgba(cr, chart->stroke_rgb[0], chart->stroke_rgb[1], chart->stroke_rgb[2], chart->stroke_rgb[3]);
231*d83cc019SAndroid Build Coastguard Worker cairo_stroke(cr);
232*d83cc019SAndroid Build Coastguard Worker break;
233*d83cc019SAndroid Build Coastguard Worker }
234*d83cc019SAndroid Build Coastguard Worker cairo_restore(cr);
235*d83cc019SAndroid Build Coastguard Worker }
236*d83cc019SAndroid Build Coastguard Worker
chart_fini(struct chart * chart)237*d83cc019SAndroid Build Coastguard Worker void chart_fini(struct chart *chart)
238*d83cc019SAndroid Build Coastguard Worker {
239*d83cc019SAndroid Build Coastguard Worker free(chart->samples);
240*d83cc019SAndroid Build Coastguard Worker }
241