4597446e176845b9509a8a6c76432fda7356acb6
[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   /*  tab=(int *)MALLOC(size*sizeof(int); */
978
979   /*   for(i=0;i<size;i++) tab[i]=log_min+i; */
980
981   *n_grads = 0 ;
982
983   if(size <= MAX_LOG_TICKS)    {
984     for(i=0;i<size;i++)
985     {
986       /*    _grads[i] = exp10(tab[i]); */
987       _grads[i] = log_min+i;
988       *n_grads = (*n_grads) + 1;
989       /*          sciprint("Juste en sortie, _grads[%d] = %lf\n",i, _grads[i]); */
990     }
991   }
992   else
993   {
994     int pas = 0, old_pas= 0,j;
995     int val = size, passed = 0;
996
997     /* Try to reduce number of ticks, by finding the greatest divider */
998     for(j=val-1;j>1;j--)
999       if(val%j == 0){
1000         old_pas = pas;
1001         pas=j; 
1002         passed = 1;
1003
1004         if((MAX_LOG_TICKS * pas)<=val){ 
1005           if(old_pas != 0) {pas = old_pas; }
1006           break;
1007         }
1008       }
1009
1010       /* If we haven't found a divider or if the number of ticks will be to large */
1011       /* Use only towo ticks */
1012       if(passed != 1 || (size/pas) >  MAX_LOG_TICKS ) { pas = size; }
1013
1014       if(pas==size)
1015       {
1016         _grads[0] = log_min;
1017         _grads[1] = log_max;
1018         *n_grads =2;
1019       }
1020       else
1021       {
1022         for(i=0;i<=(int )(size/pas);i++)
1023         {
1024           _grads[i] = log_min+(i*pas);
1025
1026           *n_grads = (*n_grads) + 1;
1027           /*        sciprint("Juste en sortie, _grads[%d] = %lf\n",i, _grads[i]); */
1028         }
1029       }
1030   }
1031
1032   return 0;
1033 }
1034
1035 /**
1036 * get the exponent used for log axis from given data bounds
1037 * @return 0 if OK, -1 if negative bounds.
1038 */
1039 int sciGetLogExponent( double minBound, double maxBound, double * expMin, double * expMax )
1040 {
1041   if ( minBound > 0 )
1042   {
1043     *expMin = floor( log10( minBound ) ) ;
1044     *expMax = ceil(  log10( maxBound ) ) ;
1045     return 0 ;
1046   }
1047   *expMax = 1.0 ;
1048   *expMin = 0.0 ;
1049   return -1 ;
1050 }
1051 /*--------------------------------------------------------------------------*/
1052 int ComputeC_format(sciPointObj * pobj, char * c_format)
1053 {
1054         int i,j;
1055         char pos;
1056         char xy_type;
1057         double *x = NULL;
1058         double *y = NULL;
1059         int *nx = NULL;
1060         int *ny = NULL;
1061         sciPointObj * psubwin = sciGetParentSubwin(pobj);
1062         int  xpassed = 0, ypassed = 0, Nx = 0, Ny = 0, x3, y3;
1063
1064
1065         if(sciGetEntityType(pobj) != SCI_AXES){
1066                 sciprint(_("Error: ComputeFormat must be used with SCI_AXES objects\n"));
1067                 return -1;
1068         }
1069
1070         pos = pAXES_FEATURE(pobj)->dir;
1071         xy_type = pAXES_FEATURE (pobj)->tics;
1072         /* Allocating space before re-copying values to not polluate the good values 
1073         that will be used inside Axes.c */
1074         if((x=MALLOC((pAXES_FEATURE (pobj)->nx)*sizeof(double)))==NULL){
1075                 sciprint(_("%s: No more memory.\n"),"ComputeC_format");
1076                 return -1;
1077         }
1078
1079         if((y=MALLOC((pAXES_FEATURE (pobj)->ny)*sizeof(double)))==NULL){
1080                 sciprint(_("%s: No more memory.\n"),"ComputeC_format");
1081                 return -1;
1082         }
1083
1084         if((nx=MALLOC(sizeof(int)))==NULL){
1085                 sciprint(_("%s: No more memory.\n"),"ComputeC_format");
1086                 return -1;
1087         }  
1088
1089         if((ny=MALLOC(sizeof(int)))==NULL){
1090                 sciprint(_("%s: No more memory.\n"),"ComputeC_format");
1091                 return -1;
1092         }
1093
1094         nx[0] = pAXES_FEATURE (pobj)->nx;
1095         for(i=0;i<(*nx);i++) { x[i] = pAXES_FEATURE(pobj)->vx[i]; }
1096
1097         ny[0] = pAXES_FEATURE (pobj)->ny;
1098         for(i=0;i<(*ny);i++) { y[i] = pAXES_FEATURE(pobj)->vy[i]; }
1099
1100         /* Algo. here */
1101         if(xy_type == 'i') {  
1102                 switch ( pos ) {
1103                         case 'u' : case 'd' :  
1104                                 if(pSUBWIN_FEATURE(psubwin)->logflags[0] == 'n')
1105                                 {
1106                                         while (x[3]>10) { x[3]=floor(x[3]/2); }
1107                                 }
1108                                 else
1109                                 {
1110                                         if(x[3] > 12)
1111                                         { /* F.Leray arbitrary value=12 for the moment */
1112                                                 x3=(int)x[3];     /* if x[3]>12 algo is triggered to search a divisor */
1113                                                 for(j=x3-1;j>1;j--)
1114                                                 {
1115                                                         if(x3%j == 0){
1116                                                                 x[3]=j; 
1117                                                                 xpassed = 1;
1118                                                         }
1119                                                 }
1120                                                 if(xpassed != 1) { x[3] = 1; }
1121                                         }
1122                                 }
1123
1124                                 break;
1125                         case 'r' : case 'l' :
1126                                 if(pSUBWIN_FEATURE(psubwin)->logflags[1] == 'n')
1127                                 {
1128                                         while (y[3]>10) { y[3]=floor(y[3]/2); }
1129                                 }
1130                                 else
1131                                 {
1132                                         if(y[3] > 12){
1133                                                 y3=(int)y[3];
1134                                                 for(j=y3-1;j>1;j--)
1135                                                 {
1136                                                         if(y3%j == 0){
1137                                                                 y[3]=j;
1138                                                                 ypassed = 1;
1139                                                         }
1140                                                 }
1141                                                 if(ypassed != 1) { y[3] = 1; }
1142                                         }
1143                                 }
1144                                 break;
1145                 }
1146         }
1147
1148
1149         /** Real to Pixel values **/
1150         switch ( xy_type ) 
1151         {
1152         case 'v' :
1153                 Nx= *nx;
1154                 Ny= *ny;
1155                 break;
1156         case 'r' :
1157                 switch ( pos ) {
1158                         case 'u' : case 'd' :
1159                                 Nx = (int) x[2]+1;
1160                                 break;
1161                         case 'r' : case 'l' :
1162                                 Ny = (int) y[2]+1;
1163                                 break;
1164                 }
1165                 break;
1166         case 'i' : 
1167                 switch ( pos ) {
1168                         case 'u' : case 'd' :
1169                                 Nx = (int) x[3]+1;
1170                                 break; 
1171                         case 'r' : case 'l' :
1172                                 Ny = (int) y[3]+1;
1173                                 break;
1174                 }
1175                 break;
1176         default: 
1177                 sciprint(_("%s: Wrong type argument %s.\n"),"Sci_Axis","xy_type");
1178         }
1179
1180         switch (pos) 
1181         {
1182         case 'u' : 
1183         case 'd' :
1184                 /** Horizontal axes **/
1185                 /** compute a format **/
1186                 switch (xy_type )
1187                 {
1188                 case 'v' :
1189                         ChoixFormatE1(c_format,x,Nx);
1190                         break;
1191                 case 'r' :
1192                         ChoixFormatE (c_format,x[0],x[1],(x[1]-x[0])/x[2]);
1193                         break;
1194                 case 'i' : 
1195                         ChoixFormatE (c_format,
1196                                                                                 (x[0] * exp10(x[2])),
1197                                                                                 (x[1] * exp10(x[2])),
1198                                                                                 ((x[1] * exp10(x[2])) - (x[0] * exp10(x[2])))/x[3]);
1199                         break; /* Adding F.Leray 06.05.04 */
1200                 }
1201                 break;
1202                 /** the horizontal segment **/
1203         case 'r' : 
1204         case 'l' :
1205
1206                 /** Vertical axes **/
1207                 switch (xy_type ) {
1208                         case 'v' :
1209                                 ChoixFormatE1(c_format,y,Ny);
1210                                 break;
1211                         case 'r' : 
1212                                 ChoixFormatE(c_format,y[0],y[1],(y[1]-y[0])/y[2]);
1213                                 break;
1214                         case 'i' : 
1215                                 ChoixFormatE (c_format,
1216                                                                                         (y[0] * exp10(y[2])),
1217                                                                                         (y[1] * exp10(y[2])),
1218                                                                                         ((y[1] * exp10(y[2])) - (y[0] * exp10(y[2])))/y[3]);
1219                                 break; /* Adding F.Leray 06.05.04 */
1220                 }
1221                 /** the vertical segment **/
1222                 break;
1223         }
1224
1225         /* c_format should be filled now */
1226
1227         FREE(x); x = NULL;
1228         FREE(y); y = NULL;
1229         FREE(nx); nx = NULL;
1230         FREE(ny); ny = NULL;
1231
1232         return 0;
1233
1234 }
1235 /*--------------------------------------------------------------------------*/
1236 int ComputeXIntervals( sciPointObj * pobj, char xy_type, double ** vector, int * N, int checkdim )
1237 {
1238   int i;
1239   sciAxes * ppaxes = pAXES_FEATURE (pobj);
1240   double * val = NULL; /* reprensents ppaxes->x or ppaxes->y */
1241   int nval;
1242
1243   int n;
1244
1245   /* draw an horizontal axis : YES (horizontal axis) or NO (vertical axis) */
1246   BOOL ishoriz = (ppaxes->nx > ppaxes->ny)? TRUE : FALSE; 
1247
1248   if(ishoriz == TRUE){
1249     val  = ppaxes->vx;
1250     nval = ppaxes->nx; 
1251   }
1252   else{
1253     val  = ppaxes->vy;
1254     nval = ppaxes->ny;
1255   }
1256
1257   if(xy_type == 'v')
1258   {
1259     *N = n = nval;
1260
1261     if((*vector = (double *) MALLOC(n*sizeof(double ))) == NULL){
1262           sciprint(_("%s: No more memory.\n"),"ComputeXIntervals");
1263       return -1;
1264     }
1265
1266     for(i=0;i<n;i++)
1267       (*vector)[i] = val[i];
1268   }
1269   else if(xy_type == 'r')
1270   {
1271     double step = 0;
1272
1273     *N = n = (int)val[2]+1; /* intervals number is given by  ppaxes->x or ppaxes->y */
1274
1275     if(checkdim){
1276       if(nval != 3)
1277         sciprint(_("Warning: %s must be changed, %s is '%s' and %s dimension is not %d.\n"),"tics_coord","xy_type","r","tics_coord",3);
1278
1279       if(nval < 3){
1280         sciprint(_("Error: %s must be changed FIRST, %s is '%s' and %s dimension < %d.\n"),"tics_coord","xy_type","r","tics_coord",3);
1281         *vector = (double *) NULL;
1282         return -1;
1283       }
1284     }
1285
1286     if((*vector = (double *) MALLOC(n*sizeof(double ))) == NULL){
1287           sciprint(_("%s: No more memory.\n"),"ComputeXIntervals");
1288       return -1;
1289     }
1290
1291     step = (val[1] - val[0])/(n-1);
1292
1293     for(i=0;i<n-1;i++)
1294       (*vector)[i] = val[0] + i*step;
1295
1296     (*vector)[n-1] = val[1]; /* xmax */
1297
1298   }
1299   else if(xy_type == 'i')
1300   {
1301     double step = 0;
1302
1303     *N = n = (int)val[3]+1;
1304
1305     if(checkdim){
1306       if(nval != 4)
1307         sciprint(_("Warning: %s must be changed, %s is '%s' and %s dimension is not %d.\n"),"tics_coord","xy_type","i","tics_coord",4);
1308
1309       if(nval < 4){
1310         sciprint(_("Error: %s must be changed FIRST, %s is '%s' and %s dimension < %d.\n"),"tics_coord","xy_type","i","tics_coord",4);
1311         *vector = (double *) NULL;
1312         return -1;
1313       }
1314     }
1315
1316     if((*vector =(double *)  MALLOC(n*sizeof(double ))) == NULL){
1317           sciprint(_("%s: No more memory.\n"),"ComputeXIntervals");
1318       return -1;
1319     }
1320
1321     step = (val[1]*exp10(val[2]) - val[0]*exp10(val[2]))/val[3];
1322
1323
1324     for(i=0;i<n-1;i++)
1325       (*vector)[i] = val[0]*exp10(val[2]) + i*step;
1326
1327     (*vector)[n-1] = val[1]*exp10(val[2]); /* xmax */
1328
1329   }
1330
1331   return 0;
1332 }
1333 /*--------------------------------------------------------------------------*/
1334 /**
1335  * Compute the default labels of an axis from the positions of the ticks.
1336  * @param[in/out] pobj the axis object
1337  * @return a string matrix containing the labels.
1338  *         Actually it is a row vector.
1339  */
1340 StringMatrix * computeDefaultTicsLabels( sciPointObj * pobj )
1341 {
1342   StringMatrix * ticsLabels = NULL   ;
1343   int            nbTics     = 0      ;
1344         char           tempFormat[5]       ;
1345   char         * c_format   = NULL   ;
1346   double       * vector     = NULL   ; /* position of labels */
1347   char           curLabelBuffer[257] ;
1348   int            i                   ;
1349
1350   if ( pAXES_FEATURE(pobj)->format == NULL )
1351   {
1352     /* we need to compute c_format */
1353     ComputeC_format( pobj, tempFormat ) ;
1354                 c_format = tempFormat;
1355   }
1356   else
1357   {
1358                 /* the format is already specified */
1359                 c_format = pAXES_FEATURE(pobj)->format;
1360   }
1361
1362   /* vector is allocated here */
1363   if( ComputeXIntervals( pobj, pAXES_FEATURE (pobj)->tics, &vector, &nbTics, 1 ) != 0 )
1364   {
1365     Scierror(999,_("Error: Bad size in %s: you must first increase the size of the %s.\n"),"tics_coord","tics_coord");
1366     return 0;
1367   }
1368
1369   /* create a vector of strings */
1370   ticsLabels = newMatrix( 1, nbTics ) ;
1371
1372   if ( curLabelBuffer == NULL )
1373   {
1374           sciprint(_("%s: No more memory.\n"),"computeDefaultTicsLabels");
1375           return NULL ;
1376   }
1377
1378   for( i = 0 ; i < nbTics ; i++ )
1379   {
1380     sprintf(curLabelBuffer, c_format, vector[i]) ; /* we can't know for sure the size of the label */
1381                                                  /* That's why it is first stored in a big array */
1382     copyStrMatElement(ticsLabels, 0, i, curLabelBuffer) ;
1383   }
1384   FREE(vector) ;
1385   vector = NULL;
1386
1387   /* I recompute the nb_tics_labels */
1388   /* Why ??? jb Silvy */
1389   pAXES_FEATURE (pobj)->nb_tics_labels = nbTics;
1390
1391   return ticsLabels ;
1392
1393 }
1394 /*--------------------------------------------------------------------------*/
1395 /* compute the c_format used for convert double to char (for labels) */
1396 int ChooseGoodFormat( char * c_format,char logflag, double *_grads,int n_grads )
1397 {
1398   int last_index = n_grads - 1;
1399
1400   if(logflag == 'l')
1401   {
1402     ChoixFormatE(c_format,
1403       exp10(_grads[0]),
1404       exp10(_grads[last_index]),
1405       (( exp10(_grads[last_index]))-( exp10(_grads[0])))/(last_index));
1406   }
1407   else
1408   {
1409     ChoixFormatE(c_format,
1410       _grads[0],
1411       _grads[last_index],
1412       ((_grads[last_index])-(_grads[0]))/(last_index)); /* Adding F.Leray 06.05.04 */
1413   }
1414
1415   return 0;
1416
1417 }
1418 /*--------------------------------------------------------------------------*/
1419 char * copyFormatedValue( double value, const char format[5], int bufferSize )
1420 {
1421   char * buffer = MALLOC( bufferSize * sizeof(char) ) ;
1422   char * res = NULL ;
1423   int resLength = 0 ;
1424
1425   if ( buffer == NULL )
1426   {
1427           sciprint(_("%s: No more memory.\n"),"copyFormatedValue");
1428           return NULL ;
1429   }
1430
1431   sprintf( buffer , format, value ) ;
1432
1433   resLength =  (int)strlen( buffer ) + 1 ; /* + 1 <=> 0 terminating char */
1434
1435   res = MALLOC( resLength * sizeof(char) ) ;
1436
1437   if ( res == NULL )
1438   {
1439           sciprint(_("%s: No more memory.\n"),"copyFormatedValue");
1440           FREE( buffer ) ;
1441           return NULL ;
1442   }
1443
1444   strncpy( res, buffer, resLength ) ;
1445
1446   FREE( buffer ) ;
1447   
1448   return res ;
1449 }
1450 /*--------------------------------------------------------------------------*/
1451 char ** copyFormatedArray( const double values[], int nbStrings, const char format[5], int bufferSize )
1452 {
1453   int i ;
1454   char ** res = MALLOC( nbStrings * sizeof(char *) ) ;
1455
1456   if ( res == NULL )
1457   {
1458           sciprint(_("%s: No more memory.\n"),"copyFormatedArray");
1459           return NULL ;
1460   }
1461
1462   for ( i = 0 ; i < nbStrings ; i++ )
1463   {
1464     res[i] = copyFormatedValue( values[i], format, bufferSize ) ;
1465   }
1466
1467   return res ;
1468
1469 }
1470 /*--------------------------------------------------------------------------*/
1471 /**************************************************
1472 * Global values which are set at this level and 
1473 * not redirected to each driver
1474 **************************************************/
1475
1476 static char FPF[32]={'\0'};
1477
1478 char * getFPF(void)
1479 {
1480   return(FPF);
1481 }
1482 /*--------------------------------------------------------------------------*/