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