Add Russian translation provided by Валерий Крувялис <valkru@mail.ru>
[xiph-mirror.git] / sushivision / scale.c
blobb4759ca8d33dfc6b8067834c0e934aa309746aae
1 /*
3 * sushivision copyright (C) 2006-2007 Monty <monty@xiph.org>
5 * sushivision is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * sushivision is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with sushivision; see the file COPYING. If not, write to the
17 * Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
22 #define _GNU_SOURCE
23 #include <math.h>
24 #include <gtk/gtk.h>
25 #include <cairo-ft.h>
26 #include <fontconfig/fontconfig.h>
27 #include <stdio.h>
28 #include <limits.h>
29 #include <ctype.h>
30 #include "sushivision.h"
31 #include "internal.h"
33 /* slider scales */
34 void sv_scale_free(sv_scale_t *in){
35 sv_scale_t *s = (sv_scale_t *)in;
36 int i;
38 if(s){
39 if(s->val_list)free(s->val_list);
40 if(s->label_list){
41 for(i=0;i<s->vals;i++)
42 free(s->label_list[i]);
43 free(s->label_list);
45 if(s->legend)free(s->legend);
46 free(s);
50 sv_scale_t *sv_scale_new(char *name, char *vals){
51 int i=0;
52 _sv_token *decl= _sv_tokenize_declparam(name);
53 _sv_token *list= _sv_tokenize_valuelist(vals);
55 // sanity check the tokenization
56 if(!decl){
57 fprintf(stderr,"sushivision: Unable to parse scale argument \"%s\".\n",name);
58 return NULL;
60 if(!list){
61 fprintf(stderr,"sushivision: Unable to parse scale argument \"%s\".\n",vals);
62 return NULL;
65 sv_scale_t *s = calloc(1, sizeof(*s));
66 s->vals = list->n;
67 s->val_list = calloc(s->vals,sizeof(*s->val_list));
68 s->label_list = calloc(s->vals,sizeof(*s->label_list));
70 for(i=0;i<s->vals;i++){
71 s->label_list[i] = strdup(list->values[i]->s);
72 s->val_list[i] = list->values[i]->v;
75 s->legend=strdup(decl->label);
76 _sv_token_free(decl);
77 _sv_token_free(list);
79 return s;
82 sv_scale_t *sv_scale_copy(sv_scale_t *in){
83 sv_scale_t *s = calloc(1, sizeof(*s));
84 int i;
86 s->vals = in->vals;
87 s->val_list = calloc(s->vals,sizeof(*s->val_list));
88 s->label_list = calloc(s->vals,sizeof(*s->label_list));
89 s->legend = strdup(in->legend);
91 for(i=0;i<s->vals;i++){
92 s->val_list[i] = in->val_list[i];
93 s->label_list[i] = strdup(in->label_list[i]);
95 return s;
98 /************************* plot and graph scalespaces *********************/
100 double _sv_scalespace_value(_sv_scalespace_t *s, double pixel){
101 double val = (double)(pixel-s->first_pixel)*s->neg/s->step_pixel + s->first_val;
102 return val * s->expm;
105 void _sv_scalespace_double(_sv_scalespace_t *s){
106 s->two_exponent--;
107 s->expm = pow(5,s->five_exponent) * pow(2,s->two_exponent);
108 s->first_val *= 2;
109 s->first_pixel *= 2;
110 s->pixels *= 2;
113 double _sv_scalespace_pixel(_sv_scalespace_t *s, double val){
114 val /= s->expm;
115 val -= s->first_val;
116 val *= s->step_pixel;
117 val *= s->neg;
118 val += s->first_pixel;
120 return val;
123 double _sv_scalespace_scaledel(_sv_scalespace_t *from, _sv_scalespace_t *to){
124 return from->expm * to->step_pixel * from->neg * to->neg / (from->step_pixel * to->expm);
127 long _sv_scalespace_scalenum(_sv_scalespace_t *from, _sv_scalespace_t *to){
128 int five = from->five_exponent - to->five_exponent;
129 int two = from->two_exponent - to->two_exponent;
130 long ret = to->step_pixel;
131 while(two-->0)
132 ret *= 2;
133 while(five-->0)
134 ret *= 5;
135 return ret*2;
138 long _sv_scalespace_scaleden(_sv_scalespace_t *from, _sv_scalespace_t *to){
139 int five = to->five_exponent - from->five_exponent;
140 int two = to->two_exponent - from->two_exponent;
141 long ret = from->step_pixel;
142 while(two-->0)
143 ret *= 2;
144 while(five-->0)
145 ret *= 5;
146 return ret*2;
149 long _sv_scalespace_scaleoff(_sv_scalespace_t *from, _sv_scalespace_t *to){
150 int fiveF = from->five_exponent - to->five_exponent;
151 int twoF = from->two_exponent - to->two_exponent;
152 int fiveT = to->five_exponent - from->five_exponent;
153 int twoT = to->two_exponent - from->two_exponent;
154 long expF = 1;
155 long expT = 1;
157 while(twoF-->0) expF *= 2;
158 while(fiveF-->0) expF *= 5;
159 while(twoT-->0) expT *= 2;
160 while(fiveT-->0) expT *= 5;
162 return (2 * from->first_val * from->step_pixel * from->neg - (2 * from->first_pixel + 1))
163 * expF * to->step_pixel
165 - (2 * to->first_val * to->step_pixel * to->neg - (2 * to->first_pixel + 1))
166 * expT * from->step_pixel;
169 long _sv_scalespace_scalebin(_sv_scalespace_t *from, _sv_scalespace_t *to){
170 int fiveF = from->five_exponent - to->five_exponent;
171 int twoF = from->two_exponent - to->two_exponent;
172 int fiveT = to->five_exponent - from->five_exponent;
173 int twoT = to->two_exponent - from->two_exponent;
174 long expF = 1;
175 long expT = 1;
177 while(twoF-->0) expF *= 2;
178 while(fiveF-->0) expF *= 5;
179 while(twoT-->0) expT *= 2;
180 while(fiveT-->0) expT *= 5;
182 return (2 * from->first_val * from->step_pixel * from->neg - (2 * from->first_pixel))
183 * expF * to->step_pixel
185 - (2 * to->first_val * to->step_pixel * to->neg - (2 * to->first_pixel))
186 * expT * from->step_pixel;
189 int _sv_scalespace_mark(_sv_scalespace_t *s, int num){
190 return s->first_pixel + s->step_pixel*num;
193 int _sv_scalespace_decimal_exponent(_sv_scalespace_t *s){
194 double val = s->two_exponent*.3 + s->five_exponent*.7;
195 if(val<0){
196 return (int)floor(val);
197 }else{
198 return (int)ceil(val);
202 double _sv_scalespace_label(_sv_scalespace_t *s, int num, char *buffer){
203 int pixel = _sv_scalespace_mark(s,num);
204 double val = _sv_scalespace_value(s,pixel);
205 int decimal_exponent = _sv_scalespace_decimal_exponent(s);
206 if(decimal_exponent<0){
207 sprintf(buffer,"%.*f",-decimal_exponent,val);
208 }else{
209 sprintf(buffer,"%.0f",val);
211 return val;
214 // name is *not* copied
215 _sv_scalespace_t _sv_scalespace_linear (double lowpoint, double highpoint, int pixels, int max_spacing, char *name){
216 double orange = fabs(highpoint - lowpoint), range;
217 _sv_scalespace_t ret;
219 int five_place;
220 int two_place;
221 long long first;
222 int neg = (lowpoint>highpoint?-1:1);
224 if(pixels<1)pixels=1;
226 memset(&ret,0,sizeof(ret)); // otherwise packing may do us in!
228 ret.lo = lowpoint;
229 ret.hi = highpoint;
230 ret.init = 1;
231 ret.pixels = pixels;
232 ret.legend = name;
233 ret.spacing = max_spacing;
235 if(orange < 1e-30*pixels){
236 // insufficient to safeguard the int64 first var below all by
237 // itself, but it will keep things on track until later checks
238 orange = 1e-30 * pixels;
239 highpoint = lowpoint + orange;
240 ret.massaged = 1;
243 while(1){
244 range = orange;
245 five_place = 0;
246 two_place = 0;
248 while(rint(pixels / range) < max_spacing){
249 five_place++;
250 two_place++;
251 range *= .1;
253 while(rint(pixels / range) > max_spacing){
254 five_place--;
255 two_place--;
256 range *= 10;
259 if (rint(pixels / (range*.2)) <= max_spacing){
260 five_place++;
261 range *= .2;
263 if (rint(pixels / (range*.5)) <= max_spacing){
264 two_place++;
265 range *= .5;
268 ret.two_exponent = two_place;
269 ret.five_exponent = five_place;
271 if(pixels == 0. || range == 0.)
272 ret.step_pixel = max_spacing;
273 else
274 ret.step_pixel = rint(pixels / range);
275 ret.expm = pow(2,two_place) * pow(5,five_place);
277 first = (long long)(lowpoint/ret.expm);
279 if(neg<0){
280 /* overflow check */
281 if(LLONG_MAX * ret.expm < highpoint){
282 lowpoint += orange/2;
283 orange *= 2;
284 highpoint = lowpoint - orange;
285 ret.massaged = 1;
286 continue;
288 }else{
289 /* overflow check */
290 if(LLONG_MAX * ret.expm < lowpoint){
291 lowpoint -= orange/2;
292 orange *= 2;
293 highpoint = lowpoint + orange;
294 ret.massaged = 1;
295 continue;
299 while((first+neg) * ret.expm * neg <= lowpoint*neg)
300 first += neg;
302 if(neg<0){
303 /* overflow check */
304 if(LLONG_MIN * ret.expm > lowpoint){
305 lowpoint += orange/2;
306 orange *= 2;
307 highpoint = lowpoint - orange;
308 ret.massaged = 1;
309 continue;
311 }else{
312 /* overflow check */
313 if(LLONG_MIN * ret.expm > highpoint){
314 lowpoint -= orange/2;
315 orange *= 2;
316 highpoint = lowpoint + orange;
317 ret.massaged = 1;
318 continue;
322 while((first-neg) * ret.expm * neg > highpoint*neg)
323 first -= neg;
325 // make sure the scale display has meaningful sig figs to work with */
326 if( first*128/128 != first ||
327 first*16*ret.expm == (first*16+neg)*ret.expm ||
328 (first*16+neg)*ret.expm == (first*16+neg*2)*ret.expm){
329 lowpoint -= orange/(neg*2);
330 orange *= 2;
331 highpoint = lowpoint + neg*orange;
332 ret.massaged = 1;
333 continue;
336 ret.first_val = first;
338 ret.first_pixel = rint((first - (lowpoint / ret.expm)) * ret.step_pixel);
340 ret.neg = neg;
341 break;
344 return ret;