422a54b89ac790cc5417f45150bfe31687591e69
[scilab.git] / scilab / modules / graphics / src / c / DrawObjects.c
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2001-2002 - INRIA - Mathieu Philipe
4  * Copyright (C) 2002-2004 - INRIA - Djalel Abdemouche
5  * Copyright (C) 2004-2006 - INRIA - Fabrice Leray
6  * Copyright (C) 2005 - INRIA - Jean-Baptiste Silvy
7  * Copyright (C) 2010 - DIGITEO - Manuel Juliachs
8  * Copyright (C) 2010 - Paul Griffiths
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  *    newGraph Library header
21  *    Comment:
22  *    This file contains all functions used to Draw the content of a window.
23  *    The main functions is sciDrawObj that draws the objects recursively.
24  ------------------------------------------------------------------------/-*/
25
26 #include "DrawObjects.h"
27 #include "GetProperty.h"
28 #include "SetProperty.h"
29 #include "BuildObjects.h"
30 #include "DestroyObjects.h"
31 #include "PloEch.h"
32 #include "sciprint.h"
33 #include "CurrentObjectsManagement.h"
34 #include "ObjectSelection.h"
35 #include "math_graphics.h"
36 #include "Format.h"
37 #include "HandleManagement.h"
38
39
40 #include "BuildDrawingObserver.h"
41 #include "DrawingBridge.h"
42
43 #include "MALLOC.h" /* MALLOC */
44 #include "localization.h"
45
46 #include "math.h" /* fabs, floor, log10, pow */
47
48
49 #define round(a)  (int)(((a)<0.0)?(a)-.5:(a)+.5)
50
51
52
53 static BOOL subwinNeedsDisplay(sciPointObj * pSubwin);
54
55
56
57 void sciRedrawFigure( void )
58 {
59   sciDrawObj(sciGetCurrentFigure ());
60 }
61
62
63 void sciClearFigure(sciPointObj * pFigure)
64 {
65   destroyGraphicsSons(pFigure);
66
67   /* recreate the subwindow */
68   createFirstSubwin(pFigure);
69
70   forceHierarchyRedraw(pFigure);
71 }
72
73 void sciXbasc()
74 {
75   sciClearFigure(sciGetCurrentFigure());
76 }
77
78 void sciXclear()
79 {
80   static sciPointObj *masousfen, *tmpsousfen;
81   sciSons *psonstmp;
82
83   tmpsousfen= sciGetCurrentSubWin();
84   psonstmp = sciGetSons (sciGetCurrentFigure());
85
86   while (psonstmp != (sciSons *) NULL)
87   {
88     if(sciGetEntityType (psonstmp->pointobj) == SCI_SUBWIN)
89     {
90       masousfen= (sciPointObj *)psonstmp->pointobj;
91       sciSetSelectedSubWin (masousfen);
92       sciSetdrawmode (FALSE);
93     }
94     psonstmp = psonstmp->pnext;
95   }
96
97   sciSetSelectedSubWin (tmpsousfen);
98   notifyObservers(sciGetCurrentFigure ());
99 }
100
101
102 /* get the displayed bounds of an axis */
103 void sciGetDisplayedBounds( sciPointObj * pSubWin,
104                             double      * xmin   ,
105                             double      * xmax   ,
106                             double      * ymin   ,
107                             double      * ymax   ,
108                             double      * zmin   ,
109                             double      * zmax    )
110 {
111   sciSubWindow * ppsubwin =  pSUBWIN_FEATURE ( pSubWin ) ;
112     /*****************************************************************
113      * get initial bounds
114    *****************************************************************/
115   if( sciGetZooming( pSubWin ) )
116   {
117     *xmin = ppsubwin->ZRect[0] ;
118     *ymin = ppsubwin->ZRect[2] ;
119     *xmax = ppsubwin->ZRect[1] ;
120     *ymax = ppsubwin->ZRect[3] ;
121     *zmin = ppsubwin->ZRect[4] ;
122     *zmax = ppsubwin->ZRect[5] ;
123   }
124   else
125   {
126     *xmin = ppsubwin->SRect[0] ;
127     *ymin = ppsubwin->SRect[2] ;
128     *xmax = ppsubwin->SRect[1] ;
129     *ymax = ppsubwin->SRect[3] ;
130     *zmin = ppsubwin->SRect[4] ;
131     *zmax = ppsubwin->SRect[5] ;
132   }
133
134
135
136   /*****************************************************************
137    * modify  bounds and aaint  if using log scaling X axis
138    *****************************************************************/
139   if ( ppsubwin->logflags[0] == 'l' )
140   {
141     if ( sciGetLogExponent( *xmin, *xmax, xmin, xmax ) != 0 )
142     {
143       sciprint(_("Warning: Can't use Log on X-axis xmin is negative.\n"));
144     }
145   }
146
147   /*****************************************************************
148    * modify  bounds and aaint  if using log scaling Y axis
149    *****************************************************************/
150   if ( ppsubwin->logflags[1] == 'l' )
151   {
152     if ( sciGetLogExponent( *ymin, *ymax, ymin, ymax ) != 0 )
153     {
154       sciprint(_("Warning: Can't use Log on Y-axis ymin is negative.\n"));
155     }
156   }
157
158   /*****************************************************************
159    * modify  bounds and aaint  if using log scaling Z axis
160    *****************************************************************/
161   if ( ppsubwin->logflags[2] == 'l' )
162   {
163     if ( sciGetLogExponent( *zmin, *zmax, zmin, zmax ) != 0 )
164     {
165       sciprint(_("Warning: Can't use Log on Z-axis zmin is negative.\n"));
166     }
167   }
168
169 }
170
171 /* F.Leray au 13.10.04 completly review for new axes graduations */
172 /*** F.Leray 02.04.04 */
173 /* FUNCTION FOR 2D UPDATE ONLY !!!!! <=> beginning of axis_3ddraw (in 2d HERE of course! ) */
174 /* Copy on update_frame_bounds */
175 BOOL sci_update_frame_bounds_2d(sciPointObj *pobj)
176 {
177   double xmax, xmin, ymin, ymax, zmin, zmax ;
178   double hx,hy,hx1,hy1;
179   int i;
180
181   sciSubWindow * ppsubwin =  pSUBWIN_FEATURE (pobj);
182   double FRect[4],WRect[4],ARect[4];
183   char logscale[2];
184
185   /* Temp variables only used when called from update_specification_bounds */
186   /* to know if we have to redraw all the figure */
187   double ExistingFRect[4]; /* the Existing FRect at start to be compared at the end of this routine */
188   /* in order to determine wheter or not the bounds have changed... */
189   int nbsubtics[2];
190   int nbgrads[2];
191   /* End of Temp variables */
192
193   for(i=0;i<4;i++) ExistingFRect[i] =  ppsubwin->FRect[i]; /* store old initial bounds*/
194
195   for(i=0;i<2;i++) nbsubtics[i] = ppsubwin->axes.nbsubtics[i];
196   nbgrads[0] = ppsubwin->axes.nxgrads;
197   nbgrads[1] = ppsubwin->axes.nygrads;
198
199   /* nbtics on z put to 0 */
200   /*   ppsubwin->axes.nzgrads = 0; */
201
202
203   sciGetDisplayedBounds( pobj, &xmin, &xmax, &ymin, &ymax, &zmin, &zmax ) ;
204
205
206   /* _grad Init. to 0. */
207   for(i=0;i<20;i++)
208     {
209       ppsubwin->axes.xgrads[i] = 0.;
210       ppsubwin->axes.ygrads[i] = 0.;
211     }
212
213
214   if ( ppsubwin->logflags[0]=='n') { /* x-axis */
215     TheTicks(&xmin, &xmax, &(ppsubwin->axes.xgrads[0]), &ppsubwin->axes.nxgrads, FALSE);
216     ppsubwin->axes.nbsubtics[0] = ComputeNbSubTics(pobj,ppsubwin->axes.nxgrads,'n',NULL,ppsubwin->axes.nbsubtics[0]); /* Nb of subtics computation and storage */ /* F.Leray 07.10.04 */
217   }
218   else{ /* log. case */
219     GradLog(xmin,xmax,ppsubwin->axes.xgrads,&ppsubwin->axes.nxgrads, FALSE );
220     ppsubwin->axes.nbsubtics[0] = ComputeNbSubTics(pobj,ppsubwin->axes.nxgrads,'l',ppsubwin->axes.xgrads,0);
221   }
222
223   if ( ppsubwin->logflags[1]=='n') { /* y-axis */
224     TheTicks(&ymin, &ymax, &(ppsubwin->axes.ygrads[0]), &ppsubwin->axes.nygrads, FALSE);
225     ppsubwin->axes.nbsubtics[1] = ComputeNbSubTics(pobj,ppsubwin->axes.nygrads,'n',NULL, ppsubwin->axes.nbsubtics[1]); /* Nb of subtics computation and storage */ /* F.Leray 07.10.04 */
226   }
227   else{ /* log. case */
228     GradLog(ymin,ymax,ppsubwin->axes.ygrads,&ppsubwin->axes.nygrads, FALSE );
229     ppsubwin->axes.nbsubtics[1] = ComputeNbSubTics(pobj,ppsubwin->axes.nygrads,'l',ppsubwin->axes.ygrads,0);
230   }
231
232   if(ppsubwin->tight_limits == FALSE )
233     {
234       xmin = ppsubwin->axes.xgrads[0];
235       xmax = ppsubwin->axes.xgrads[ ppsubwin->axes.nxgrads - 1];
236       ymin = ppsubwin->axes.ygrads[0];
237       ymax = ppsubwin->axes.ygrads[ ppsubwin->axes.nygrads - 1];
238     }
239
240   /*****************************************************************
241    * modify  bounds if  isoview requested
242    *****************************************************************/
243   if ( ppsubwin->isoview == TRUE) {
244     int wdim[2];
245
246     wdim[0] = sciGetWindowWidth(sciGetParentFigure(pobj));
247     wdim[1] = sciGetWindowHeight(sciGetParentFigure(pobj));
248
249     hx=xmax-xmin;
250     hy=ymax-ymin;
251     getscale2d(WRect,FRect,logscale,ARect);
252
253     wdim[0]=linint((double)wdim[0] *WRect[2]);
254     wdim[1]=linint((double)wdim[1] *WRect[3]);
255
256     if ( hx/(double)wdim[0]  <hy/(double) wdim[1] ) {
257       hx1=wdim[0]*hy/wdim[1];
258       xmin=xmin-(hx1-hx)/2.0;
259       xmax=xmax+(hx1-hx)/2.0;
260     }
261     else {
262       hy1=wdim[1]*hx/wdim[0];
263       ymin=ymin-(hy1-hy)/2.0;
264       ymax=ymax+(hy1-hy)/2.0;
265     }
266
267     /* F.Leray 28.09.04 */
268     /* I need to recompute the correct xgrads and ygrads vector to have a good display */
269
270     if ( ppsubwin->logflags[0]=='n') { /* x-axis */
271       TheTicks(&xmin, &xmax, &(ppsubwin->axes.xgrads[0]), &ppsubwin->axes.nxgrads, FALSE);
272       ppsubwin->axes.nbsubtics[0] = ComputeNbSubTics(pobj,ppsubwin->axes.nxgrads,'n',NULL, ppsubwin->axes.nbsubtics[0]); /* Nb of subtics computation and storage */ /* F.Leray 07.10.04 */
273     }
274     else{ /* log. case */
275       GradLog(xmin,xmax,ppsubwin->axes.xgrads,&ppsubwin->axes.nxgrads, FALSE);
276       ppsubwin->axes.nbsubtics[0] = ComputeNbSubTics(pobj,ppsubwin->axes.nxgrads,'l',ppsubwin->axes.xgrads,0);
277     }
278
279
280
281     if ( ppsubwin->logflags[1]=='n') { /* y-axis */
282       TheTicks(&ymin, &ymax, &(ppsubwin->axes.ygrads[0]), &ppsubwin->axes.nygrads, FALSE);
283       ppsubwin->axes.nbsubtics[1] = ComputeNbSubTics(pobj,ppsubwin->axes.nygrads,'n',NULL, ppsubwin->axes.nbsubtics[1]); /* Nb of subtics computation and storage */ /* F.Leray 07.10.04 */
284     }
285     else{ /* log. case */
286       GradLog(ymin,ymax,ppsubwin->axes.ygrads,&ppsubwin->axes.nygrads, FALSE );
287       ppsubwin->axes.nbsubtics[1] = ComputeNbSubTics(pobj,ppsubwin->axes.nygrads,'l',ppsubwin->axes.ygrads,0);
288     }
289
290
291     /* END ISO if */
292   }
293
294
295
296
297   /*****************************************************************
298    * set the actual bounds in subwindow data structure
299    *****************************************************************/
300
301
302   ppsubwin->FRect[0]=xmin;
303   ppsubwin->FRect[2]=xmax;
304   ppsubwin->FRect[1]=ymin;
305   ppsubwin->FRect[3]=ymax;
306
307
308   for(i=0;i<4;i++)
309     if(ppsubwin->FRect[i] != ExistingFRect[i]){
310       return TRUE;
311       break;
312     }
313
314   for(i=0;i<2;i++)
315     if(nbsubtics[i] != ppsubwin->axes.nbsubtics[i]){
316       return TRUE;
317       break;
318     }
319
320   if(nbgrads[0] != ppsubwin->axes.nxgrads) return TRUE;
321   if(nbgrads[1] != ppsubwin->axes.nygrads) return TRUE;
322
323   return FALSE;
324 }
325
326 /**update_3dbounds -> renammed sci_update_frame_bounds_3d
327  * @author Djalel Abdemouche 10/2003
328  * Should be in Plo2dEch.c file
329  */
330 BOOL sci_update_frame_bounds_3d(sciPointObj *pobj)
331 {
332   double xmin,xmax,ymin,ymax,zmin,zmax;
333   int i;
334   sciSubWindow * ppsubwin = pSUBWIN_FEATURE (pobj);
335
336   /* Temp variables only used when called from update_specification_bounds */
337   /* to know if we have to redraw all the figure */
338   double ExistingFRect[6]; /* the Existing FRect at start to be compared at the end of this routine */
339   /* in order to determine wheter or not the bounds have changed... */
340   int nbsubtics[3];
341   int nbgrads[3];
342   /* End of Temp variables */
343
344   for(i=0;i<6;i++) ExistingFRect[i] =  ppsubwin->FRect[i]; /* store old initial bounds*/
345
346   for(i=0;i<3;i++) nbsubtics[i] = ppsubwin->axes.nbsubtics[i];
347   nbgrads[0] = ppsubwin->axes.nxgrads;
348   nbgrads[1] = ppsubwin->axes.nygrads;
349   nbgrads[2] = ppsubwin->axes.nzgrads;
350
351   sciGetDisplayedBounds( pobj, &xmin, &xmax, &ymin, &ymax, &zmin, &zmax ) ;
352
353
354   /* _grad Init. to 0. */
355   for(i=0;i<20;i++)
356     {
357       ppsubwin->axes.xgrads[i] = 0.;
358       ppsubwin->axes.ygrads[i] = 0.;
359       ppsubwin->axes.zgrads[i] = 0.;
360     }
361
362
363   if ( ppsubwin->logflags[0]=='n') { /* x-axis */
364     TheTicks(&xmin, &xmax, &(ppsubwin->axes.xgrads[0]), &ppsubwin->axes.nxgrads, FALSE);
365     ppsubwin->axes.nbsubtics[0] = ComputeNbSubTics(pobj,ppsubwin->axes.nxgrads,'n',NULL,ppsubwin->axes.nbsubtics[0]); /* Nb of subtics computation and storage */
366   }
367   else{ /* log. case */
368     GradLog(xmin,xmax,ppsubwin->axes.xgrads,&ppsubwin->axes.nxgrads, FALSE );
369     ppsubwin->axes.nbsubtics[0] = ComputeNbSubTics(pobj,ppsubwin->axes.nxgrads,'l',ppsubwin->axes.xgrads,0);
370   }
371
372   if ( ppsubwin->logflags[1]=='n') { /* y-axis */
373     TheTicks(&ymin, &ymax, &(ppsubwin->axes.ygrads[0]), &ppsubwin->axes.nygrads, FALSE);
374     ppsubwin->axes.nbsubtics[1] = ComputeNbSubTics(pobj,ppsubwin->axes.nygrads,'n',NULL, ppsubwin->axes.nbsubtics[1]); /* Nb of subtics computation and storage */
375   }
376   else{ /* log. case */
377     GradLog(ymin,ymax,ppsubwin->axes.ygrads,&ppsubwin->axes.nygrads, FALSE );
378     ppsubwin->axes.nbsubtics[1] = ComputeNbSubTics(pobj,ppsubwin->axes.nygrads,'l',ppsubwin->axes.ygrads,0);
379   }
380
381   if ( ppsubwin->logflags[2]=='n') { /* z-axis */
382     TheTicks(&zmin, &zmax, &(ppsubwin->axes.zgrads[0]), &ppsubwin->axes.nzgrads, FALSE);
383     ppsubwin->axes.nbsubtics[2] = ComputeNbSubTics(pobj,ppsubwin->axes.nzgrads,'n',NULL, ppsubwin->axes.nbsubtics[2]); /* Nb of subtics computation and storage */
384   }
385   else{ /* log. case */
386     GradLog(zmin,zmax,ppsubwin->axes.zgrads,&ppsubwin->axes.nzgrads, FALSE );
387     ppsubwin->axes.nbsubtics[2] = ComputeNbSubTics(pobj,ppsubwin->axes.nzgrads,'l',ppsubwin->axes.zgrads,0);
388   }
389
390   if(ppsubwin->tight_limits == FALSE )
391     {
392       xmin = ppsubwin->axes.xgrads[0];
393       xmax = ppsubwin->axes.xgrads[ ppsubwin->axes.nxgrads - 1];
394       ymin = ppsubwin->axes.ygrads[0];
395       ymax = ppsubwin->axes.ygrads[ ppsubwin->axes.nygrads - 1];
396       zmin = ppsubwin->axes.zgrads[0];
397       zmax = ppsubwin->axes.zgrads[ ppsubwin->axes.nzgrads - 1];
398     }
399
400
401   ppsubwin->FRect[0]=xmin;
402   ppsubwin->FRect[2]=xmax;
403   ppsubwin->FRect[1]=ymin;
404   ppsubwin->FRect[3]=ymax;
405   ppsubwin->FRect[4]=zmin;
406   ppsubwin->FRect[5]=zmax;
407
408
409
410   for(i=0;i<6;i++)
411     if(ppsubwin->FRect[i] != ExistingFRect[i]){
412       return TRUE;
413       break;
414     }
415
416   for(i=0;i<3;i++)
417     if(nbsubtics[i] != ppsubwin->axes.nbsubtics[i]){
418       return TRUE;
419       break;
420     }
421
422   if(nbgrads[0] != ppsubwin->axes.nxgrads) return TRUE;
423   if(nbgrads[1] != ppsubwin->axes.nygrads) return TRUE;
424   if(nbgrads[2] != ppsubwin->axes.nzgrads) return TRUE;
425
426   return FALSE;
427 }
428
429
430
431
432
433
434 /** ComputeNbSubTics. Compute an appropriate number of subtics based on the number of major ticks,
435  * the tick graduations, and the axes scaling (log or normal).  If auto subtics is off, then nbsubtics_input is returned.
436  * If the axis scaling is linear and the major tick graduations lie along multiples of 10^n, where n is the greatest
437  * integer such that 10^n is less than the graduation step size, then the number of subtics is selected to
438  * place subtics also at multiples of 10^n. If major ticks are at every multiple of 10^n, a heuristic is used to
439  * compute the number of subtics within a graduation. This heuristic assigns more subtics as the number of major
440  * ticks decreases. If the graduations are not provided (grads = NULL), the heuristic is used.
441  *
442  * For logarithmic scaling, the number of subticks returned is 8 if the major tick graduations are at every factor of 10.
443  * Subtics are suppressed (0 is returned) if the number of major ticks exceeds a fixed threshold. If major tick
444  * graduations are separated by factors of 10^n (n>1) then the number of subtics is selected to place subtics
445  * at factors of 10.
446  *
447  * (Update 8/24/2010 by Paul Griffiths to resolve poor choice of subtics. See bug#6686.)
448  *
449  * @param pobj Pointer to a sciSubWindow.
450  * @param nbtics Number of major ticks.
451  * @param logflag Character value of 'l' or 'n' that indicates log or normal axis scaling, respectively.
452  * @param grads Value of major tick graduations. May be NULL.
453  * @param nbsubtics_input Value returned if auto subtics feature is disabled.
454  * @return Number of subticks to display.
455  */
456 int ComputeNbSubTics(sciPointObj * pobj, int nbtics, char logflag, const double * grads, int nbsubtics_input)
457 {
458   /* Parameters for calculating the number of subtics */
459   const int subticsval_len = 13; /* <--- MUST MATCH LENGTH OF subticsval */
460   /** Lookup-table Heuristic for number of subtics based on the number of tics */
461   const int subticsval[] =      {0,0,19,9,7,4,4,3,2,2,1 ,1, 0};
462   const int dec_subticsval[] =  {0,0, 9,9,4,4,4,4,1,1,1 ,1, 0};
463   /** Maximum subtics beyond the heuristic when fitting subtics along integer intervals of base 10. */
464   const int max_extra_tics = 2;
465   /** Threshold remainder used to decide if one number is a mulitple of the other. */
466   const double mult_thrsh = 1e-6;
467   /** Threshold number of major ticks above which subtics are supressed in logarithmic-scaling. */
468   const int lognbtics_thrsh  = 7;
469
470   double grads_diff;        /* Used for computing spacing between major ticks. */
471   int nbtics_safe = nbtics; /* nbtics clamped to the range 0 to subticsval_len-1. Safe as an index into subticsval. */
472
473   sciSubWindow * ppsubwin = pSUBWIN_FEATURE (pobj);
474
475   if (nbtics_safe < 0 )
476   {
477     nbtics_safe = 0;
478   }
479   else if (nbtics_safe >= subticsval_len)
480   {
481     nbtics_safe = subticsval_len - 1;
482   }
483
484   if(logflag =='l')
485   {
486     /* If tics are at every power of 10, then return 8 subtics
487      * If tics are at every 10^n (n>1), then place subtics at powers of 10. */
488
489     /* Without provided graduations, suggest 8. */
490     if( grads == NULL )
491     {
492       return 8; /* This may or may not be a good value but it maintains this function's old behavior. */
493     }
494
495     /* We need at least two tics to be able to place subtics. */
496     if( nbtics < 2 )
497     {
498       return 0;
499     }
500
501     /* Compute average. (Note that nbtics >= 2.) */
502     grads_diff = (grads[nbtics-1] - grads[0] ) / (nbtics-1);
503     grads_diff = fabs( grads_diff );  // Make into a positive difference.
504
505     /* Check that graduations are actually on powers of 10 (not just spaced by factors of 10) */
506     if( fabs( round( grads[0] ) - grads[0] ) >=  mult_thrsh )
507     {
508       return 0; /* Not on powers of 10. Suppress subtics. */
509     }
510
511     /* If grads_diff is nearly 1.0 (i.e. major graduations are at every factor of 10)
512      * then return 8 unless there are too many major ticks. */
513     if( fabs(grads_diff - 1.0) < mult_thrsh )
514     {
515       if( nbtics < lognbtics_thrsh )
516       {
517          return 8; /* show logarithmic subdivision */
518       }
519       else
520       {
521         return 0; /* Too many major ticks -- suppress subtics. */
522       }
523     }
524     else
525     {
526       /* Try to place subtics at each factor 10 */
527       int nbsubtics = round( grads_diff ) - 1;
528
529       /* Use the heuristic to guide the maximum allowable subtics based on the
530        * the number of major tics. */
531       if( nbsubtics <= subticsval[ nbtics_safe ] )
532       {
533         return /* nbsubtics */ 0;  /* !! We have to suppress subtics because the subtic drawer assumes linear spacing between subtics. */
534       }
535       else
536       {
537         return 0;
538       }
539     }
540   }
541   else /* linear scaling case */
542   {
543     if(ppsubwin->flagNax == FALSE) /* if auto subtics mode == ON */
544     {
545       double intbase10 = 0.;
546       /* Without graduations, use the heuristic */
547       if( grads == NULL )
548       {
549         return subticsval[nbtics_safe];
550       }
551
552       /* We need at least two tics to be able to place subtics. */
553       if( nbtics < 2 )
554       {
555         return 0;
556       }
557
558       /* Compute average graduation. (Note that nbtics >= 2.) */
559       grads_diff = (grads[nbtics-1] - grads[0]) / (double)(nbtics-1);
560       grads_diff = fabs( grads_diff );  /* Make into a positive difference. */
561
562       /* Compute the largest integral power of 10 smaller than grads_diff. */
563       intbase10 = pow(10, floor( log10(grads_diff) ) );
564
565       /* Check if grads_diff is very close to a multiple of intbase10 -- if not, try one power of 10 lower */
566       if( fabs( round( grads_diff/intbase10 ) - grads_diff/intbase10 ) >= mult_thrsh )
567       {
568         intbase10 /= 10;
569       }
570
571       if( fabs( round( grads_diff/intbase10 ) - grads_diff/intbase10 ) < mult_thrsh )
572       {
573         /* Place subtics at integer multiples of intbase10  */
574         int intvls = round( grads_diff / intbase10 );
575
576         /* If ticks are already placed at every multiple of intbase10, use the heuristic to subdivide. */
577         if( intvls == 1 )
578         {
579           return dec_subticsval[ nbtics_safe ]; /* Use heuristic */
580         }
581         else
582         {
583           /* It may be necessary to use multiples of intbase10 to have an acceptable number of subtics.
584            * Find a divisor from 1-9 such that nbsubtics+1 is evenly divisible and use the heuristic
585            * plus max_extra_tics as a maximum number of subtics. */
586           int d;
587
588           for( d=1; d < 10; d++ )
589           {
590             int max_subtics = subticsval[ nbtics_safe ]; /* compute just once */
591
592             /* Check divisibility by d. */
593             if( intvls % d != 0 )
594             {
595               continue;
596             }
597
598             /* Compare nbsubtics with the heuristic subticsval[i].  */
599             if( (intvls/d - 1) <= max_subtics )
600             {
601               return intvls/d - 1; /* subtics on intervals of intbase10 */
602             }
603           }
604           
605           return 0;  /* Cannot fit enough subtics to cover intervals using m*intbase10 (0<m<10).  */
606         }
607       }
608       else /* Did not find a reasonable integer multiple of 10^n along which to place subtics. */
609       {
610         return 0;
611       }
612     }
613     else /* if auto subtics mode == OFF already computed in Plo2dn.c, Champ.c routines... */
614     {  /* or given via a.subtics=[nbsubtics_on_x, nbsubtics_on_y, nbsubtics_on_z] command */
615       return nbsubtics_input;
616     }
617   }
618
619   return -1;
620 }
621
622
623
624 /**DrawAxesIfRequired
625  * Draws Axes (only the basic  graphicobject under subwindows) in its SubWindow or figure
626  * if and only if pFIGURE_FEATURE(pobj)->auto_redraw == TRUE !!
627  * Only used inside High Level functions calls (sucha as plot2d, plot3d...)
628  * @param sciPointObj * pobj: the pointer to the entity
629  * @return  int 0 if OK, -1 if not
630  */
631 void DrawAxesIfRequired(sciPointObj * pobj)
632 {
633   sciPointObj * pfigure = sciGetParentFigure(pobj);
634
635   if( sciGetIsAutoDrawable(pfigure) && sciGetVisibility(pfigure) )
636   {
637     DrawAxes(pobj);
638   }
639
640 }
641
642 /* Routine used inside Plo2dn.c, Champ.c, Gray.c... */
643 /* to force the drawing of the axes after a new object is created */
644 void DrawAxes(sciPointObj * pobj)
645 {
646   sciPointObj * psubwin = sciGetParentSubwin(pobj);
647   sciDrawObj(psubwin);
648 }
649
650 /*---------------------------------------------------------------------------------*/
651 /**
652  * draw the figure number numFigure.
653  */
654 void sciDrawFigure( int numFigure )
655 {
656   int curFigure = sciGetNumFigure( sciGetCurrentFigure() ) ;
657   sciSetUsedWindow( numFigure ) ;
658   sciDrawObj( sciGetCurrentFigure() ) ;
659   sciSetUsedWindow( curFigure ) ;
660 }
661 /*---------------------------------------------------------------------------------*/
662
663
664
665
666 /**sciDrawObjIfRequired
667  * Draws Object (only the basic  graphicobject under subwindows) in its SubWindow or figure
668  * if and only if pFIGURE_FEATURE(pobj)->auto_redraw == TRUE !!
669  * Only used inside High Level functions calls (sucha as plot2d, plot3d...)
670  * @param sciPointObj * pobj: the pointer to the entity
671  * @return  int 0 if OK, -1 if not
672  */
673 int
674 sciDrawObjIfRequired (sciPointObj * pobj)
675 {
676   /*sciPointObj * pfigure = sciGetParentFigure(pobj);
677
678   if( sciGetIsAutoDrawable(pfigure) && sciGetVisibility(pfigure) )
679   {
680     sciDrawObj( pobj ) ;
681   }*/
682
683   sciDrawObj( pobj ) ;
684
685   return 0;
686 }
687 /*---------------------------------------------------------------------------------*/
688 void showPixmap(sciPointObj * pFigure)
689 {
690   /* Hack here. Pixmap has same action as drawlater() */
691   /* So we just draw the figure here to make it appear */
692   if (sciGetPixmapMode(pFigure))
693   {
694     sciSetPixmapMode(pFigure, FALSE);
695     sciDrawObj(pFigure);
696     sciSetPixmapMode(pFigure, TRUE);
697     sciDrawObj(pFigure);
698   }
699 }
700 /*---------------------------------------------------------------------------------*/
701 void clearPixmap(sciPointObj * pFigure)
702 {
703   // nothing to do with the hack
704 }
705 /*---------------------------------------------------------------------------------*/
706 BOOL needsDisplay(sciPointObj * pFigure)
707 {
708   /* return false if the figure contains no or one subwindow and the subwindow is not displayed. */
709
710   if (!sciGetVisibility(pFigure))
711   {
712     /* Figure not visible */
713     return FALSE;
714   }
715   else if (sciGetNbTypedObjects(pFigure, SCI_SUBWIN) == 0)
716   {
717     /* No subwindows, return false */
718     return FALSE;
719   }
720   else if (sciGetNbTypedObjects(pFigure, SCI_SUBWIN) == 1)
721   {
722     /* One subwindow check if it is visible */
723     sciPointObj * onlySubwin = sciGetFirstTypedSelectedSon(pFigure, SCI_SUBWIN);
724     return subwinNeedsDisplay(onlySubwin);
725   }
726   else
727   {
728     return TRUE;
729   }
730 }
731 /*---------------------------------------------------------------------------------*/
732 static BOOL subwinNeedsDisplay(sciPointObj * pSubwin)
733 {
734   /* the subwindow is not displayed if it does not have any children, its box is of and is transparent or */
735   /* has the same background as the figure */
736   if (!sciGetVisibility(pSubwin))
737   {
738     /* subwin invisible */
739     return FALSE;
740   }
741   else if (sciGetNbChildren(pSubwin) > 4)
742   {
743     /* Other children than the labels */
744     return TRUE;
745   }
746   else
747   {
748     BOOL axesVisible[3];
749
750     if (sciGetBoxType(pSubwin) != BT_OFF)
751     {
752       /* Box is displayed */
753       return TRUE;
754     }
755
756     sciGetAxesVisible(pSubwin, axesVisible);
757     if (axesVisible[0] || axesVisible[1] || axesVisible[2])
758     {
759       /* One axis is visible */
760       return TRUE;
761     }
762
763     if (   sciGetIsFilled(pSubwin)
764         && sciGetBackground(sciGetParentFigure(pSubwin)) != sciGetBackground(pSubwin))
765     {
766       /* Compare subwin background and figure one */
767       return TRUE;
768     }
769
770     /* Check that labels texts are empty */
771     if (   !sciisTextEmpty(pSUBWIN_FEATURE(pSubwin)->mon_title)
772         || !sciisTextEmpty(pSUBWIN_FEATURE(pSubwin)->mon_x_label)
773         || !sciisTextEmpty(pSUBWIN_FEATURE(pSubwin)->mon_y_label)
774         || !sciisTextEmpty(pSUBWIN_FEATURE(pSubwin)->mon_z_label))
775     {
776       return TRUE;
777     }
778
779     /* apparently no need to display the axes */
780     return FALSE;
781   }
782 }
783 /*---------------------------------------------------------------------------------*/
784 #undef round