Coverity #1097868, #1097733 fixed
[scilab.git] / scilab / modules / graphics / src / c / Format.c
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 1998-2001 - ENPC - Jean-Philippe Chancelier
4  * Copyright (C) 2001 - INRIA - Fran├žois Delebecque
5  * Copyright (C) 2004-2006 - INRIA - Fabrice Leray
6  * Copyright (C) 2006 - INRIA - Jean-Baptiste Silvy
7  * Copyright (C) 2009 - DIGITEO - Pierre Lando
8  * Copyright (C) 2011 - DIGITEO - Manuel Juliachs
9  *
10  * Copyright (C) 2012 - 2016 - Scilab Enterprises
11  *
12  * This file is hereby licensed under the terms of the GNU GPL v2.0,
13  * pursuant to article 5.3.4 of the CeCILL v.2.1.
14  * This file was originally licensed under the terms of the CeCILL v2.1,
15  * and continues to be available under such terms.
16  * For more information, see the COPYING file which you should have received
17  * along with this program.
18  *
19  */
20
21 /*------------------------------------------------------------------------
22  *    Graphic library
23  *    Copyright (C) 1998-2001 Enpc/Jean-Philippe Chancelier
24  *    jpc@cermics.enpc.fr
25  --------------------------------------------------------------------------*/
26 /*------------------------------------------------------------------------
27  * Axis drawing for 2d plots (format selection)
28  *
29  * void  ChoixFormatE(fmt, desres, xmin, xmax, xpas) : find a format
30  * void  ChoixFormatE1(fmt, desres, xx, nx)          : find a format
31  * int   C2F(graduate)(xmi,xma,xi,xa,np1,np2,kminr,kmaxr,ar)
32  *                : change [xmi,xmax] for pretty graduation
33  *--------------------------------------------------------------------------*/
34
35 #if defined(__linux__)
36 #define _GNU_SOURCE /* Bug 5673 fix: avoid dependency on GLIBC_2.7 */
37 #endif
38
39 #include <stdio.h>
40 #include <string.h>
41 #include "math_graphics.h"
42 #include "Format.h"
43 #include "sci_malloc.h"
44 #include "GetProperty.h"
45 #include "BasicAlgos.h"
46 #include "sciprint.h"
47 #include "localization.h"
48 #include "Scierror.h"
49 #include "machine.h"
50 #include "numericconstants_interface.h"
51
52 #include "getGraphicObjectProperty.h"
53 #include "graphicObjectProperties.h"
54 #include "Sciwarning.h"
55
56 #define MAX(A,B) ((A<B)?B:A)
57
58 /** Maximum of ticks for log mode */
59 #define MAX_LOG_TICKS 15
60
61 /* end here */
62
63 static void FormatPrec (char *fmt, int *desres, double xmin, double xmax,
64                         double xpas);
65 static void FormatPrec1 (char *fmt, int *desres, double *xx, int nx);
66 static int Fsepare (char *fmt, int dec, int *l, double xmin, double xmax,
67                     double xpas);
68 static int Fsepare1 (char *fmt, int dec, int *l, double *xx, int nx);
69 static void graduate1 (double *xmi, double* xma, double* xi, double* xa,
70                        int * np1, int * np2, int * kminr, int * kmaxr, int * ar, int count);
71
72 static void gradua (double *xmi, double *xma, int * kminr, int *kmaxr, int *ar, int *npr, int *b);
73 static void decompSup (double x, int * xk, int *  xa, int   b);
74 static void decompInf (double x, int * xk, int *  xa, int   b);
75
76 static void removeIndex(double* changedArray, int size, int ind);
77 static void removeBadTicks(double* ticks, BOOL * removedTicks, int * nbTicks);
78 static void GradFixedlog(double minVal, double maxVal, double* ticks, int nbGrads);
79 static int GradLog(double _min, double _max, double *_grads, int *n_grads, int compNgrads);
80
81 /**
82  * ChoixFormatE returns a format ("%.*f" or "%.*e")
83  * in fmt given xmin,xmax,pas.
84  *   fmt : character string
85  * fmt gives a format which can be used to display
86  * number in range xmin:step:xmax
87  * Exemple : ChoixFormatE(format,min,max,step);
88  *           fprintf(format,min+k*step);
89  * The format is searched so as to give distinct values
90  * for the numeric values xmin + k*xpas in [xmin,xmax]
91  * and give enough precision.
92  */
93 static void ChoixFormatE(char *fmt, double xmin, double xmax, double xpas)
94 {
95     char c = 0;
96     int des = 0, len = 0;
97     /* format f minimal  */
98     for (des = 0 ; des < 5 ; des++)
99     {
100         if (Fsepare("%.*f", des, &len, xmin, xmax, xpas))
101         {
102             break;
103         }
104     }
105     if (des < 5 && len <= 6)
106     {
107         c = 'f';
108         strcpy(fmt, "%.*f");
109     }
110     else
111     {
112         for (des = 0 ; des < 5 ; des++)
113         {
114             if (Fsepare("%.*e", des, &len, xmin, xmax, xpas))
115             {
116                 break;
117             }
118         }
119         c = 'e';
120         strcpy(fmt, "%.*e");
121     }
122     FormatPrec(fmt, &des, xmin, xmax, xpas);
123     sprintf(fmt, "%%.%d%c", des, c);
124 }
125
126 /*
127  *  checks if given format gives enough precision
128  *  if not increase it (i.e increase desres)
129  */
130
131 static void FormatPrec(char *fmt, int *desres, double xmin, double xmax, double xpas)
132 {
133     char buf1[100], buf2[100];
134     int i = 0;
135     while (xmin + ((double)i)*xpas < xmax && *desres  < 10)
136     {
137         double x1, x2, yy1;
138         yy1 = xmin + ((double) i) * xpas;
139         sprintf(buf1, fmt, *desres, yy1);
140         sprintf(buf2, fmt, *desres, yy1 + xpas);
141         sscanf(buf1, "%lf", &x1);
142         sscanf(buf2, "%lf", &x2);
143         if (  Abs((x2 - x1 - xpas) / xpas) >= 0.1)
144         {
145             *desres += 1;
146         }
147         if (  Abs((x1 - yy1) / xpas) >= 0.01)
148         {
149             *desres += 1;
150         }
151         i++;
152     }
153 }
154
155 /*
156  *  checks if format fmt gives different values for numbers
157  *  from xmin to xmax with step xpas. It also returns in variable l
158  *  the string length that will result in using the format
159  */
160
161 static int Fsepare(char *fmt, int dec, int *l, double xmin, double xmax, double xpas)
162 {
163     double x = xmin;
164     char buf1[100], buf2[100];
165     *l = 0;
166     /**  Take care of : sprintf(buf1,"%.*f",0,1.d230) which overflow in buf1 **/
167     /**  we don't use %.*f format if numbers are two big **/
168     if (strcmp("%.*f", fmt) == 0 && (Abs(xmax) > 1.e+10 || Abs(xmin) > 1.e+10))
169     {
170         return (0);
171     }
172     sprintf(buf1, fmt, dec, xmin);
173     while (x < xmax)
174     {
175         x += xpas;
176         strcpy(buf2, buf1);
177         sprintf(buf1, fmt, dec, x);
178         *l = (((int)strlen(buf1) >= *l) ? (int) strlen(buf1) : *l);
179         if (strcmp(buf1, buf2) == 0)
180         {
181             return (0);
182         }
183     }
184     return (1);
185 }
186
187 void ChoixFormatE1(char *fmt, double *xx, int nx)
188 {
189     char c = 0;
190     int des = 0, len = 0;
191     /* format f minimal  */
192     for (des = 0 ; des < 5 ; des++)
193     {
194         if (Fsepare1("%.*f", des, &len, xx, nx))
195         {
196             break;
197         }
198     }
199     if (des < 5 && len <= 6)
200     {
201         c = 'f';
202         strcpy(fmt, "%.*f");
203     }
204     else
205     {
206         for (des = 0 ; des < 5 ; des++)
207         {
208             if (Fsepare1("%.*e", des, &len, xx, nx))
209             {
210                 break;
211             }
212         }
213         c = 'e';
214         strcpy(fmt, "%.*e");
215     }
216     FormatPrec1(fmt, &des, xx, nx);
217     sprintf(fmt, "%%.%d%c", des, c);
218 }
219
220
221 /*----------------------------------------------------------
222  *  checks if format fmt gives different values for numbers
223  *  from xmin to xmax with step xpas. It also returns in variable l
224  *  the string length that will result in using the format
225  *------------------------------------------------------*/
226
227 static void FormatPrec1(char *fmt, int *desres, double *xx, int nx)
228 {
229     char buf1[100], buf2[100];
230     double xpas = 0.;
231     int i = 0;
232     while (i < nx - 1 && *desres  < 10)
233     {
234         double x1 = 0., x2 = 0.;
235         sprintf(buf1, fmt, *desres, xx[i]);
236         sprintf(buf2, fmt, *desres, xx[i + 1]);
237         sscanf(buf1, "%lf", &x1);
238         sscanf(buf2, "%lf", &x2);
239         xpas = xx[i + 1] - xx[i];
240         if (xpas != 0.0)
241         {
242             if (Abs((x2 - x1 - xpas) / xpas) >= 0.1)
243             {
244                 *desres += 1;
245             }
246             if (Abs((x1 - xx[i]) / xpas) >= 0.1)
247             {
248                 *desres += 1;
249             }
250         }
251         i++;
252     }
253 }
254
255 static int Fsepare1(char *fmt, int dec, int *l, double *xx, int nx)
256 {
257     char buf1[100], buf2[100];
258     int i = 0;
259     *l = 0;
260     /**  Take care of : sprintf(buf1,"%.*f",0,1.d230) which overflow in buf1 **/
261     /**  we don't use %.*f format if numbers are two big **/
262     if (strcmp("%.*f", fmt) == 0 && (Abs(xx[nx - 1]) > 1.e+10 || Abs(xx[0]) > 1.e+10))
263     {
264         return (0);
265     }
266     sprintf(buf1, fmt, dec, xx[0]);
267     for (i = 1 ; i < nx ; i++)
268     {
269         strcpy(buf2, buf1);
270         sprintf(buf1, fmt, dec, xx[i]);
271         *l = (((int)strlen(buf1) >= *l) ? (int) strlen(buf1) : *l);
272         if (strcmp(buf1, buf2) == 0)
273         {
274             return (0);
275         }
276     }
277     return (1);
278 }
279
280 /*----------------------------------------------------
281  * int C2F(graduate)(xmi,xma,xi,xa,np1,np2,kminr,kmaxr,ar)
282  * (xgraduate at Scilab level)
283  * Rescale an interval so as to find a pretty graduation
284  * for [xmi,xma] given seeks (xi,xa,np1,np2)
285  * such that  xi <= xmi <= xmax <= xa
286  * with xi et xa  numbers of type  kminr 10^ar and kmaxr 10^ar.
287  * then the interval [xi,xa] can be splited in *np2 sub-intervals
288  *  (kminr-kmaxr can be divided by *np2)
289  *  x_i= (kminr + i*(kmaxr-kminr)/ (*np2))*10^ar;
290  * i=0:(*np2)
291  * ecah of the  np2 intervals can in turn be splited in np1 ungraduated
292  * subintervals
293  * [np1,np2] follow the nax parameters of plot2d.
294  *
295  *  We also want to keep np2 small (*np2 <=10)
296  *  and we want [xi,xa] to be as close as possible to the interval
297  *  [xmi,xma]
298  *---------------------------------------------------- */
299
300 int C2F(graduate)(double *xmi, double *xma, double *xi, double *xa, int *np1, int *np2, int *kminr, int *kmaxr, int *ar)
301 {
302     if (*xmi > *xma)
303     {
304         double xma1 = *xmi, xmi1 = *xma;
305         graduate1(&xmi1, &xma1, xi, xa, np1, np2, kminr, kmaxr, ar, 0);
306     }
307     else
308     {
309         graduate1(xmi, xma, xi, xa, np1, np2, kminr, kmaxr, ar, 0);
310     }
311     return (0);
312 }
313
314 static void graduate1(double *xmi, double *xma, double *xi, double *xa, int *np1, int *np2, int *kminr, int *kmaxr, int *ar, int count)
315 {
316     int npr = 0, b = 0, i = 0, dx = 0, dxmi = 0, dxma = 0;
317     /* fprintf(stderr,"[%20.10f,%20.10f]\n",*xmi,*xma); */
318     /*
319      *
320      */
321     dx   = ((*xma) != (*xmi)) ? (int) ceil(log10(Abs((*xma) - (*xmi)))) : 0;
322     dxmi = (*xmi != 0) ? (int) ceil(log10(Abs((*xmi)))) : 0;
323     dxma = (*xma != 0) ? (int) ceil(log10(Abs((*xma)))) : 0;
324     dx = Max(dx - dxmi, dx - dxma);
325     /* il faut limiter b de sorte que dans la decomposition */
326     /* avec b les nombres entiers manipules ne deviennent pas trop grands */
327     /* on choisit donc b < 10 en considerant que le plus grand entier est */
328     /* 0x7FFFFFFF */
329     /* on prends aussi un b minimum de 3 : pour avoir des intervalles */
330     /* plus serr'es  : ce nombre est 'eventuellement a affiner      */
331     b = Max(-dx + 2, 3);
332     /* fprintf(stderr,"choix de b=%d",b); */
333     if (b >= 10)
334     {
335         double xmi1 = 0., xma1 = 0.;
336         int iexp = 0;
337         /* fprintf(stderr,"je ne peux decomposer les 2 nombres sont identiques\n"); */
338         /*
339         a la precision donnee les deux nombre ne peuvent etre decomposer
340         kmin,kmax devrait sinon depasser maxint
341         on les ecarte de ce qu'il faut pour pouvoir
342         les separer.
343         Attention : il faut faire attention de bien choisir iexp
344         pour ne pas boucler la dedans
345         */
346         iexp = 9 - dxmi - 1;
347         xmi1 = *xmi - exp10((double) - iexp);
348         xma1 = *xmi + exp10((double) - iexp);
349         if (count > 1)
350         {
351             sciprint(_("Internal Error: Loop in graduate1\n"));
352             sciprint(_("Please send a Bug report to dev@lists.scilab.org\n"));
353         }
354         graduate1(&xmi1, &xma1, xi, xa, np1, np2, kminr, kmaxr, ar, count + 1);
355         return;
356     }
357     while (b >= 1)
358     {
359         /* fprintf(stderr,"\tAppel avec b=%d\n",b); */
360         gradua(xmi, xma, kminr, kmaxr, ar, &npr, &b);
361         *xi = (*kminr) * exp10((double) * ar);
362         *xa = (*kmaxr) * exp10((double) * ar);
363         /** fprintf(stderr,"\tRes=[%20.10f,%20.10f]-->[%d,%d,10^%d,%d]\n",*xi,*xa
364             ,*kminr,*kmaxr,*ar,npr); */
365         *np2 = npr;
366         if (*np2 <= 20)
367         {
368             break;
369         }
370         else
371         {
372             b--;
373         }
374     }
375     /*
376       on veut essayer de ne pas depasser 10 intervalles (*np2 <= 10)
377       pour les intervalle ou on ecrit un nombre,
378       or on peut en avoir jusqu'a 20. On regarde si le nombre d'intervalle
379       est divisible. on aura alors une graduation en np2 pour l'ecriture
380       des nombres et une sous graduation np1 juste avec des tirets.
381       */
382     *np1 = 2 ;
383     if ( *np2 <= 10 )
384     {
385         return ;
386     }
387     /* le nombre est > 10 : s'il est impair on rajoute 1
388        pour diviser par deux */
389     if (*np2 % 2 == 1)
390     {
391         int step;
392         step = (*kmaxr - *kminr) / (*np2);
393         (*np2)++;
394         *kmaxr += step;
395         *xa =  (*kmaxr) * exp10((double) * ar);
396     }
397     /* On recherche des diviseurs a nouveaux pour diminuer le nombre
398        d'intervalles */
399     for (i = 2 ; i <= 10 ; i++)
400     {
401         if (*np2 % i == 0)
402         {
403             *np1 = i, *np2 /= i;
404             return;
405         }
406     }
407     *np1 = *np2;
408     *np2 = 1;
409 }
410
411 /*
412  *  renvoit kminr,kmaxr et ar tels que
413  *  [kminr*10^ar,kmaxr*10^ar] contient [xmi,xma]
414  *  b est un parametre de decompSup,decompInf
415  *  on doit avoir a l'appel xmi < xma.
416  *  le choix se fait entre deux intervalles possibles
417  *  on choisit celui qui est le plus proche de [xmi,xma]
418  *  a condition que (kmaxr-kminr) <= 20
419  *  pour b=1 on sait que (kmaxr-kminr) <= 20
420  *  20 intervalles au plus (que l'on obtient si xmin et xmax sont
421  *  de signe opposes sinon c'est 10)
422  */
423
424 /* np2, and np1 must be smaller than maxint */
425
426 #define DMAX 0xFFFFFFF
427
428 static void gradua(double *xmi, double *xma, int *kminr, int *kmaxr, int *ar, int *npr, int *b)
429 {
430     double x0 = *xmi, x1 = *xma, loc = 0.;
431     int x0k = 0, x0a = 0;
432     int x1k = 0, x1a = 0;
433     int kmin1 = 0, kmax1 = 0, a1 = 0, np1 = 0, kmin2 = 0, kmax2 = 0, a2 = 0, np2 = 0, kmin = 0, kmax = 0, a = 0, np = 0;
434     decompInf(x0, &x0k, &x0a, *b);
435     decompSup(x1, &x1k, &x1a, *b);
436     /** special cases **/
437     if (x1 == 0.0)
438     {
439         x1a = x0a;
440     }
441     if (x0 == 0.0)
442     {
443         x0a = x1a;
444     }
445     loc = Min(floor(x0 * exp10((double) - x1a)), ((double)DMAX));
446     if (loc < 0)
447     {
448         loc = Max(loc, -((double) DMAX));
449     }
450     kmin1 = (int) loc;
451     kmax1 = x1k;
452     np1 = Abs(kmax1 - kmin1);
453     np1 = (np1 < 0) ? DMAX : np1;
454     if (np1 > 10)
455     {
456         if  ((np1 % 2) == 0)
457         {
458             np1 /= 2;
459         }
460         else
461         {
462             np1++;
463             np1 /= 2;
464             kmax1++;
465         }
466     }
467     a1 = x1a;
468     /* fprintf(stderr,"\t\tsols : [%d,%d].10^%d,n=%d\t",kmin1,kmax1,a1,np1);  */
469     kmin2 = x0k;
470     loc = Min(ceil(x1 * exp10((double) - x0a)), ((double)DMAX));
471     kmax2 = (int) loc;
472     np2 = Abs(kmax2 - kmin2);
473     np2 = (np2 < 0) ? DMAX : np2;
474     if (np2 > 10)
475     {
476         if (np2 % 2 == 0)
477         {
478             np2 /= 2;
479         }
480         else
481         {
482             np2++;
483             kmin2--;
484         }
485     }
486     a2 = x0a;
487     /* fprintf(stderr,"[%d,%d].10^%d=%d\n",kmin2,kmax2,a2,np2);  */
488     if (np1 * exp10((double)a1) < np2 * exp10((double) a2))
489     {
490         if (np1 <= 20)
491         {
492             kmin = kmin1;
493             kmax = kmax1;
494             np = np1;
495             a = a1;
496         }
497         else
498         {
499             kmin = kmin2;
500             kmax = kmax2;
501             np = np2;
502             a = a2;
503         }
504     }
505     else
506     {
507         if (np2 <= 20)
508         {
509             kmin = kmin2;
510             kmax = kmax2;
511             np = np2;
512             a = a2;
513         }
514         else
515         {
516             kmin = kmin1;
517             kmax = kmax1;
518             np = np1;
519             a = a1;
520         }
521     }
522     *kminr = kmin;
523     *kmaxr = kmax;
524     *ar = a;
525     *npr = np;
526     if (kmin == kmax)
527     {
528         /*
529          * a la precision demandee les deux [xi,xa] est reduit a un point
530          * on elargit l'intervalle
531          */
532         /* fprintf(stderr,"Arg : kmin=kmax=%d",kmin) ; */
533         /* fprintf(stderr," a=%d, x0=%f,x1=%f\n",a,x0,x1); */
534         (*kminr)--;
535         (*kmaxr)++;
536         *npr = 2;
537     };
538 }
539
540 /*
541  * soit x > 0 reel fixe et b entier fixe : alors il existe un unique couple
542  * (k,a) dans NxZ avec k dans [10^(b-1)+1,10^b] tel que
543  * (k-1)*10^a < x <= k 10^a
544  * donne par  a = ceil(log10(x))-b et k=ceil(x/10^a)
545  * decompSup renvoit xk=k et xa=a
546  * si x < 0 alors decompSup(x,xk,xa,b)
547  *    s'obtient par decompInf(-x,xk,xa,b) et xk=-xk
548  * Remarque : la taille de l'entier k obtenu est controle par b
549  * il faut choisir b < 10 pour ne pas depasser dans k l'entier maximum
550  */
551
552 static void decompSup(double x, int *xk, int *xa, int b)
553 {
554     if (x == 0.0)
555     {
556         *xk = 0;
557         *xa = 1; /* jpc */
558     }
559     else
560     {
561         if (x > 0)
562         {
563             double xd;
564             static double epsilon;
565             static int first = 0;
566             if (first == 0)
567             {
568                 epsilon = 10.0 * nc_eps();
569                 first++;
570             }
571             /* if x is very near (k+1)10^a (epsilon machine)
572              * we increment xk
573              */
574             *xa = (int) ceil(log10(x)) - b;
575             *xk = (int) ceil(x / exp10((double) * xa));
576             xd = (*xk - 1) * exp10((double) * xa);
577             if (Abs((x - xd) / x) < epsilon)
578             {
579                 *xk -= 1;
580             }
581         }
582         else
583         {
584             decompInf(-x, xk, xa, b);
585             *xk = -(*xk);
586         }
587     }
588 }
589
590
591 /*
592  * soit x > 0 alors il existe un unique couple
593  * (k,a) dans NxZ avec k in [10^(b-1),10^b-1] tel que
594  * (k)*10^a <= x < (k+1) 10^a
595  * donne par
596  * a = floor(log10(x))-b+1 et k = floor(x/10^a)
597  * decompInf renvoit xk=k et xa=a
598  * si x < 0 alors decompInf(x,xk,xa,b)
599  *    s'obtient par decompSup(-x,xk,xa,b) et xk=-xk
600  */
601
602 static void decompInf(double x, int *xk, int *xa, int b)
603 {
604     if (x == 0.0)
605     {
606         *xk = 0;
607         *xa = 1; /* jpc */
608     }
609     else
610     {
611         if (x > 0)
612         {
613             double xup;
614             static double epsilon;
615             static int first = 0;
616             if (first == 0)
617             {
618                 epsilon = 10.0 * nc_eps();
619                 first++;
620             }
621             *xa = (int) floor(log10(x)) - b + 1;
622             *xk = (int) floor(x / exp10((double) * xa));
623             /* if x is very near (k+1)10^a (epsilon machine)
624              * we increment xk
625              */
626             xup = (*xk + 1) * exp10((double) * xa);
627             if (Abs((x - xup) / x) < epsilon)
628             {
629                 *xk += 1;
630             }
631         }
632         else
633         {
634             decompSup(-x, xk, xa, b);
635             *xk = -(*xk);
636         }
637     }
638 }
639
640 /*--------------------------------------------------------------------------*/
641 /* remove an element in the array from translating the next
642 elements on step backward */
643 static void removeIndex(double* changedArray, int size, int ind)
644 {
645     int i  = 0;
646     for (i = ind + 1 ; i < size ; i++)
647     {
648         changedArray[i - 1] = changedArray[i];
649     }
650 }
651 /*--------------------------------------------------------------------------*/
652 /* remove in the ticks array the indices i such as removedTicks[i] */
653 /* is true. The value nbtics is an in-out variable */
654 static void removeBadTicks(double* curTicks, BOOL * removedTicks, int * nbTicks)
655 {
656     int i  = 0;
657     for (i = *nbTicks - 1 ; i >= 0 ; i--)
658     {
659         if (removedTicks[i])
660         {
661             removeIndex(curTicks, *nbTicks, i);
662             *nbTicks = *nbTicks - 1;
663         }
664     }
665 }
666 /*--------------------------------------------------------------------------*/
667 /* compute the graduation of the segment [minVal,maxVal] knowing the number of ticks */
668 static void GradFixedlog(double minVal, double maxVal, double* outTicks, int nbGrads)
669 {
670     int initSize  = 0;
671     int i = 0;
672
673     /* initialize the array as usual */
674     double tempTicks[20];
675     GradLog(minVal, maxVal, tempTicks, &initSize, FALSE);
676
677     if (initSize > nbGrads)
678     {
679         /* we create a smaller vector from a bigger one */
680         int nbRemove = initSize - nbGrads;
681
682         BOOL * removedTicks = NULL;
683         if ((removedTicks = MALLOC(initSize * sizeof(BOOL))) == NULL)
684         {
685             return;
686         }
687
688         for (i = 0 ; i < initSize ; i++)
689         {
690             removedTicks[i] = FALSE;
691         }
692
693         /* we now remove the nbremove indexes : round((0.5 + i) * size / nbRemove) */
694         /* i=0..nbReg-1 should do the thing */
695         for (i = 0 ; i < nbRemove ; i++)
696         {
697             int remIndex = 1 + (int) scilab_round( i  * ((double) initSize - 2) / ((double) nbRemove));
698             removedTicks[remIndex] = TRUE;
699         }
700
701         removeBadTicks(tempTicks, removedTicks, &initSize);
702
703         FREE(removedTicks);
704
705     }
706     doubleArrayCopy(outTicks, tempTicks, nbGrads);
707
708 }
709
710
711 /* compute the automatic graduation of the segment [_min,_max] and store it in _grads */
712 /* the number of graduation may be fixed if compNgrads is TRUE or automatically computed */
713 /* otherwise. */
714 static int GradLog(double   _min   ,
715                    double   _max   ,
716                    double* _grads ,
717                    int    * n_grads,
718                    int      compNgrads)
719 {
720     int i = 0;
721     int log_min = 0, log_max = 0;
722     int size = 0;
723
724     if (compNgrads)
725     {
726         GradFixedlog(_min, _max, _grads, *n_grads);
727         return 0;
728     }
729
730     log_max =  (int) ceil(_max);
731     log_min =  (int) floor(_min);
732
733     /* If _min == _max, enlarge the interval*/
734     if (log_max == log_min)
735     {
736         log_max++;
737         log_min--;
738     }
739
740     size = log_max - log_min + 1;
741
742     *n_grads = 0;
743
744     if (size <= MAX_LOG_TICKS)
745     {
746         for (i = 0; i < size; i++)
747         {
748             _grads[i] = log_min + i;
749             *n_grads = (*n_grads) + 1;
750         }
751     }
752     else
753     {
754         int pas = 0, old_pas = 0, j;
755         int val = size, passed = 0;
756
757         /* Try to reduce number of ticks, by finding the greatest divider */
758         for (j = val - 1; j > 1; j--)
759             if (val % j == 0)
760             {
761                 old_pas = pas;
762                 pas = j;
763                 passed = 1;
764
765                 if ((MAX_LOG_TICKS * pas) <= val)
766                 {
767                     if (old_pas != 0)
768                     {
769                         pas = old_pas;
770                     }
771                     break;
772                 }
773             }
774
775         /* If we haven't found a divider or if the number of ticks will be to large */
776         /* Use only towo ticks */
777         if (passed != 1 || (size / pas) >  MAX_LOG_TICKS)
778         {
779             pas = size;
780         }
781
782         if (pas == size)
783         {
784             _grads[0] = log_min;
785             _grads[1] = log_max;
786             *n_grads = 2;
787         }
788         else
789         {
790             for (i = 0; i <= (int)(size / pas); i++)
791             {
792                 _grads[i] = log_min + (i * pas);
793
794                 *n_grads = (*n_grads) + 1;
795             }
796         }
797     }
798
799     return 0;
800 }
801
802 /**
803 * get the exponent used for log axis from given data bounds
804 * @return 0 if OK, -1 if negative bounds.
805 */
806 int sciGetLogExponent(double minBound, double maxBound, double* expMin, double* expMax)
807 {
808     if (minBound > 0)
809     {
810         *expMin = floor(log10(minBound));
811         *expMax = ceil( log10(maxBound));
812         return 0;
813     }
814     *expMax = 1.0;
815     *expMin = 0.0;
816     return -1;
817 }
818 /*--------------------------------------------------------------------------*/
819 /*
820  * This function has been adapted to the MVC framework (property get calls)
821  * in order to be able to provide a valid format string when computing
822  * default labels for the Axis object. The algorithm is left untouched.
823  * Its code ought to be put within the Java part of the Model.
824  */
825 int ComputeC_format(int iObjUID, char * c_format)
826 {
827     int i = 0, j = 0;
828     int pos = 0;
829     int* piPos = &pos;
830     int xy_type = 0;
831     int* piXy_type = &xy_type;
832     int nx = 0;
833     int* piNx = &nx;
834     int ny = 0;
835     int* piNy = &ny;
836     double *x = NULL;
837     double *y = NULL;
838     double* tmpx = NULL;
839     double* tmpy = NULL;
840     int iType = -1;
841     int *piType = &iType;
842     int  xpassed = 0, ypassed = 0, Nx = 0, Ny = 0, x3, y3;
843     int parentAxesID;
844     int * piParentAxesID = &parentAxesID;
845     int logFlag = 0;
846     int* piLogFlag = &logFlag;
847
848     getGraphicObjectProperty(iObjUID, __GO_TYPE__, jni_int, (void **)&piType);
849
850     if (iType != __GO_AXIS__)
851     {
852         Scierror(999, _("Error: ComputeFormat must be used with AXIS objects\n"));
853         return -1;
854     }
855
856     getGraphicObjectProperty(iObjUID, __GO_PARENT_AXES__, jni_int, (void **)&piParentAxesID);
857
858     getGraphicObjectProperty(iObjUID, __GO_TICKS_DIRECTION__, jni_int, (void **)&piPos);
859     getGraphicObjectProperty(iObjUID, __GO_TICKS_STYLE__, jni_int, (void **)&piXy_type);
860
861     getGraphicObjectProperty(iObjUID, __GO_X_NUMBER_TICKS__, jni_int, (void **)&piNx);
862     getGraphicObjectProperty(iObjUID, __GO_Y_NUMBER_TICKS__, jni_int, (void **)&piNy);
863
864     /* Allocating space before re-copying values to not pollute the good values
865     that will be used inside Axes.c */
866     if ((x = MALLOC(nx * sizeof(double))) == NULL)
867     {
868         Scierror(999, _("%s: No more memory.\n"), "ComputeC_format");
869         return -1;
870     }
871
872     if ((y = MALLOC(ny * sizeof(double))) == NULL)
873     {
874         Scierror(999, _("%s: No more memory.\n"), "ComputeC_format");
875         FREE(x);
876         return -1;
877     }
878
879     getGraphicObjectProperty(iObjUID, __GO_X_TICKS_COORDS__, jni_double_vector, (void **)&tmpx);
880     getGraphicObjectProperty(iObjUID, __GO_Y_TICKS_COORDS__, jni_double_vector, (void **)&tmpy);
881
882     for (i = 0; i < nx; i++)
883     {
884         x[i] = tmpx[i];
885     }
886
887     for (i = 0; i < ny; i++)
888     {
889         y[i] = tmpy[i];
890     }
891
892     /* Algo. here */
893     if (xy_type == 2)
894     {
895         if (pos == 0 || pos == 1)
896         {
897             getGraphicObjectProperty(iObjUID, __GO_X_AXIS_LOG_FLAG__, jni_int, (void **)&piLogFlag);
898
899             if (logFlag == 0)
900             {
901                 while (x[3] > 10)
902                 {
903                     x[3] = floor(x[3] / 2);
904                 }
905             }
906             else
907             {
908                 if (x[3] > 12)
909                 {
910                     /* F.Leray arbitrary value=12 for the moment */
911                     x3 = (int)x[3];   /* if x[3]>12 algo is triggered to search a divisor */
912                     for (j = x3 - 1; j > 1; j--)
913                     {
914                         if (x3 % j == 0)
915                         {
916                             x[3] = j;
917                             xpassed = 1;
918                         }
919                     }
920                     if (xpassed != 1)
921                     {
922                         x[3] = 1;
923                     }
924                 }
925             }
926         }
927         else if (pos == 2 || pos == 3)
928         {
929             getGraphicObjectProperty(iObjUID, __GO_Y_AXIS_LOG_FLAG__, jni_int, (void **)&piLogFlag);
930
931             if (logFlag == 0)
932             {
933                 while (y[3] > 10)
934                 {
935                     y[3] = floor(y[3] / 2);
936                 }
937             }
938             else
939             {
940                 if (y[3] > 12)
941                 {
942                     y3 = (int)y[3];
943                     for (j = y3 - 1; j > 1; j--)
944                     {
945                         if (y3 % j == 0)
946                         {
947                             y[3] = j;
948                             ypassed = 1;
949                         }
950                     }
951                     if (ypassed != 1)
952                     {
953                         y[3] = 1;
954                     }
955                 }
956             }
957         }
958     }
959
960
961     /** Real to Pixel values **/
962     if (xy_type == 0)
963     {
964         Nx = nx;
965         Ny = ny;
966     }
967     else if (xy_type == 1)
968     {
969         if (pos == 0 || pos == 1)
970         {
971             Nx = (int) x[2] + 1;
972         }
973         else if (pos == 2 || pos == 3)
974         {
975             Ny = (int) y[2] + 1;
976         }
977     }
978     else if (xy_type == 2)
979     {
980         if (pos == 0 || pos == 1)
981         {
982             Nx = (int) x[3] + 1;
983         }
984         else if (pos == 2 || pos == 3)
985         {
986             Ny = (int) y[3] + 1;
987         }
988     }
989     else
990     {
991         Scierror(999, _("%s: Wrong type argument %s.\n"), "Sci_Axis", "xy_type");
992         FREE(x);
993         x = NULL;
994         FREE(y);
995         y = NULL;
996         return -1;
997     }
998
999     if (pos == 0 || pos == 1)
1000     {
1001         /** Horizontal axes **/
1002         /** compute a format **/
1003         if (xy_type == 0)
1004         {
1005             ChoixFormatE1(c_format, x, Nx);
1006         }
1007         else if (xy_type == 1)
1008         {
1009             ChoixFormatE (c_format, x[0], x[1], (x[1] - x[0]) / x[2]);
1010         }
1011         else if (xy_type == 2)
1012         {
1013             ChoixFormatE (c_format,
1014                           (x[0] * exp10(x[2])),
1015                           (x[1] * exp10(x[2])),
1016                           ((x[1] * exp10(x[2])) - (x[0] * exp10(x[2]))) / x[3]);
1017             /* Adding F.Leray 06.05.04 */
1018         }
1019         /** the horizontal segment **/
1020     }
1021     else if (pos == 2 || pos == 3)
1022     {
1023         /** Vertical axes **/
1024         if (xy_type == 0)
1025         {
1026             ChoixFormatE1(c_format, y, Ny);
1027         }
1028         else if (xy_type == 1)
1029         {
1030             ChoixFormatE(c_format, y[0], y[1], (y[1] - y[0]) / y[2]);
1031         }
1032         else if (xy_type == 2)
1033         {
1034             ChoixFormatE (c_format,
1035                           (y[0] * exp10(y[2])),
1036                           (y[1] * exp10(y[2])),
1037                           ((y[1] * exp10(y[2])) - (y[0] * exp10(y[2]))) / y[3]);
1038             /* Adding F.Leray 06.05.04 */
1039         }
1040         /** the vertical segment **/
1041     }
1042
1043     /* c_format should be filled now */
1044
1045     FREE(x);
1046     x = NULL;
1047     FREE(y);
1048     y = NULL;
1049
1050     return 0;
1051 }
1052 /*--------------------------------------------------------------------------*/
1053 /*
1054  * This function has been updated for the MVC (property get calls).
1055  * Its code ought to be put within the Java part of the Model.
1056  */
1057 int ComputeXIntervals(int iObjUID, char xy_type, double ** vector, int * N, int checkdim)
1058 {
1059     int i = 0;
1060     double* val = NULL; /* represents the x or y ticks coordinates */
1061     int nval = 0;
1062
1063     int n = 0;
1064     int nx = 0;
1065     int* piNx = &nx;
1066     int ny = 0;
1067     int* piNy = &ny;
1068     BOOL ishoriz = FALSE;
1069
1070     getGraphicObjectProperty(iObjUID, __GO_X_NUMBER_TICKS__, jni_int, (void **)&piNx);
1071     getGraphicObjectProperty(iObjUID, __GO_Y_NUMBER_TICKS__, jni_int, (void **)&piNy);
1072
1073     /* draw an horizontal axis : YES (horizontal axis) or NO (vertical axis) */
1074     ishoriz = (nx > ny) ? TRUE : FALSE;
1075
1076     if (ishoriz == TRUE)
1077     {
1078         getGraphicObjectProperty(iObjUID, __GO_X_TICKS_COORDS__, jni_double_vector, (void **)&val);
1079         nval = nx;
1080     }
1081     else
1082     {
1083         getGraphicObjectProperty(iObjUID, __GO_Y_TICKS_COORDS__, jni_double_vector, (void **)&val);
1084         nval = ny;
1085     }
1086
1087     if (xy_type == 'v')
1088     {
1089         *N = n = nval;
1090
1091         if ((*vector = (double *) MALLOC(n * sizeof(double))) == NULL)
1092         {
1093             Scierror(999, _("%s: No more memory.\n"), "ComputeXIntervals");
1094             return -1;
1095         }
1096
1097         for (i = 0; i < n; i++)
1098         {
1099             (*vector)[i] = val[i];
1100         }
1101     }
1102     else if (xy_type == 'r')
1103     {
1104         double step = 0;
1105
1106         *N = n = (int)val[2] + 1; /* intervals number is given by  ppaxes->x or ppaxes->y */
1107
1108         if (checkdim)
1109         {
1110             if (nval != 3)
1111             {
1112                 Sciwarning(_("Warning: %s must be changed, %s is '%s' and %s dimension is not %d.\n"), "tics_coord", "xy_type", "r", "tics_coord", 3);
1113             }
1114
1115             if (nval < 3)
1116             {
1117                 Scierror(999, _("%s must be changed FIRST, %s is '%s' and %s dimension < %d.\n"), "tics_coord", "xy_type", "r", "tics_coord", 3);
1118                 *vector = (double *) NULL;
1119                 return -1;
1120             }
1121         }
1122
1123         if ((*vector = (double *) MALLOC(n * sizeof(double))) == NULL)
1124         {
1125             Scierror(999, _("%s: No more memory.\n"), "ComputeXIntervals");
1126             return -1;
1127         }
1128
1129         step = (val[1] - val[0]) / (n - 1);
1130
1131         for (i = 0; i < n - 1; i++)
1132         {
1133             (*vector)[i] = val[0] + i * step;
1134         }
1135
1136         (*vector)[n - 1] = val[1]; /* xmax */
1137
1138     }
1139     else if (xy_type == 'i')
1140     {
1141         double step = 0;
1142
1143         *N = n = (int)val[3] + 1;
1144
1145         if (checkdim)
1146         {
1147             if (nval != 4)
1148             {
1149                 Sciwarning(_("Warning: %s must be changed, %s is '%s' and %s dimension is not %d.\n"), "tics_coord", "xy_type", "i", "tics_coord", 4);
1150             }
1151
1152             if (nval < 4)
1153             {
1154                 Scierror(999, _("%s must be changed FIRST, %s is '%s' and %s dimension < %d.\n"), "tics_coord", "xy_type", "i", "tics_coord", 4);
1155                 *vector = (double *) NULL;
1156                 return -1;
1157             }
1158         }
1159
1160         if ((*vector = (double *)  MALLOC(n * sizeof(double))) == NULL)
1161         {
1162             Scierror(999, _("%s: No more memory.\n"), "ComputeXIntervals");
1163             return -1;
1164         }
1165
1166         step = (val[1] * exp10(val[2]) - val[0] * exp10(val[2])) / val[3];
1167
1168
1169         for (i = 0; i < n - 1; i++)
1170         {
1171             (*vector)[i] = val[0] * exp10(val[2]) + i * step;
1172         }
1173
1174         (*vector)[n - 1] = val[1] * exp10(val[2]); /* xmax */
1175
1176     }
1177
1178     return 0;
1179 }
1180 /*--------------------------------------------------------------------------*/
1181 /**
1182  * Compute the default labels of an axis from the positions of the ticks.
1183  * @param[in/out] pobjUID the axis object UID
1184  * @return a string matrix containing the labels.
1185  *         Actually it is a row vector.
1186  */
1187 StringMatrix * computeDefaultTicsLabels(int iObjUID)
1188 {
1189     StringMatrix * ticsLabels = NULL  ;
1190     int            nbTics     = 0     ;
1191     char           tempFormat[5]      ;
1192     char         * c_format   = NULL  ;
1193     double       * vector     = NULL   ; /* position of labels */
1194     char           curLabelBuffer[257];
1195     int            i = 0;
1196
1197     int tmp = 0;
1198     int* piTmp = &tmp;
1199     char ticksStyle = 'v';
1200
1201     getGraphicObjectProperty(iObjUID, __GO_FORMATN__, jni_string, (void **)&c_format);
1202
1203     /*
1204      * If different from the empty string, the format is already specified,
1205      * if equal, it needs to be computed.
1206      */
1207     if (strcmp(c_format, "") == 0)
1208     {
1209         ComputeC_format(iObjUID, tempFormat);
1210         c_format = tempFormat;
1211     }
1212
1213     getGraphicObjectProperty(iObjUID, __GO_TICKS_STYLE__, jni_int, (void **)&piTmp);
1214
1215     if (tmp == 0)
1216     {
1217         ticksStyle = 'v';
1218     }
1219     else if (tmp == 1)
1220     {
1221         ticksStyle = 'r';
1222     }
1223     else if (tmp == 2)
1224     {
1225         ticksStyle = 'i';
1226     }
1227
1228     /* vector is allocated here */
1229     if (ComputeXIntervals(iObjUID, ticksStyle, &vector, &nbTics, 1) != 0)
1230     {
1231         Scierror(999, _("Bad size in %s: you must first increase the size of the %s.\n"), "tics_coord", "tics_coord");
1232         return 0;
1233     }
1234
1235     /* create a vector of strings */
1236     ticsLabels = newMatrix(1, nbTics);
1237     if (ticsLabels == NULL)
1238     {
1239         Scierror(999, _("%s: No more memory.\n"), "computeDefaultTicsLabels");
1240         return NULL;
1241     }
1242
1243     for (i = 0 ; i < nbTics ; i++)
1244     {
1245         sprintf(curLabelBuffer, c_format, vector[i]) ; /* we can't know for sure the size of the label */
1246         /* That's why it is first stored in a big array */
1247         copyStrMatElement(ticsLabels, 0, i, curLabelBuffer);
1248     }
1249
1250     FREE(vector);
1251     vector = NULL;
1252
1253     return ticsLabels;
1254
1255 }
1256 /*--------------------------------------------------------------------------*/
1257 /**
1258  * Create a new string which is the result the conversion of a double value
1259  * using a certain format
1260  * @param bufferSize size of the buffer used to store the store before the copying
1261  *                   it to the result. It must greater than the length of the returning string.
1262  *                   and ideally the same length.
1263  * @return the newly created strings, or NULL if an error occurred.
1264  */
1265 static char * copyFormatedValue(double value, const char format[5], int bufferSize)
1266 {
1267     char * buffer = (char*)MALLOC(bufferSize * sizeof(char));
1268     char * res = NULL;
1269     int resLength = 0;
1270
1271     if (buffer == NULL)
1272     {
1273         return NULL;
1274     }
1275
1276     sprintf(buffer , format, value);
1277
1278     resLength =  (int)strlen(buffer) + 1 ; /* + 1 <=> 0 terminating char */
1279
1280     res = (char*)MALLOC(resLength * sizeof(char));
1281
1282     if (res == NULL)
1283     {
1284         FREE(buffer);
1285         return NULL;
1286     }
1287
1288     strncpy(res, buffer, resLength);
1289
1290     FREE(buffer);
1291
1292     return res;
1293 }
1294 /*--------------------------------------------------------------------------*/
1295 char ** copyFormatedArray(const double values[], int nbStrings, const char format[5], int bufferSize)
1296 {
1297     int i = 0;
1298     char ** res = MALLOC(nbStrings * sizeof(char *));
1299
1300     if (res == NULL)
1301     {
1302         return NULL;
1303     }
1304
1305     for (i = 0 ; i < nbStrings ; i++)
1306     {
1307         res[i] = copyFormatedValue(values[i], format, bufferSize);
1308     }
1309
1310     return res;
1311
1312 }
1313 /*--------------------------------------------------------------------------*/
1314 /**************************************************
1315 * Global values which are set at this level and
1316 * not redirected to each driver
1317 **************************************************/
1318
1319 static char FPF[32] = {'\0'};
1320
1321 char * getFPF(void)
1322 {
1323     return (FPF);
1324 }
1325 /*--------------------------------------------------------------------------*/