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