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