xref: /petsc/src/sys/classes/draw/utils/axis.c (revision 1c059edd3db9f31a91cf15abd818f139b7459992)
1 
2 #include <../src/sys/classes/draw/utils/axisimpl.h>
3 
4 #undef __FUNCT__
5 #define __FUNCT__ "PetscRint"
6 static PetscErrorCode PetscRint(PetscReal x,PetscReal *result)
7 {
8   PetscFunctionBegin;
9   if (x > 0) *result = floor(x + 0.5);
10   else       *result = floor(x - 0.5);
11   PetscFunctionReturn(0);
12 }
13 
14 #undef __FUNCT__
15 #define __FUNCT__ "PetscDrawAxisSetLimits"
16 /*@
17     PetscDrawAxisSetLimits -  Sets the limits (in user coords) of the axis
18 
19     Not Collective (ignored on all processors except processor 0 of PetscDrawAxis)
20 
21     Input Parameters:
22 +   axis - the axis
23 .   xmin,xmax - limits in x
24 -   ymin,ymax - limits in y
25 
26     Options Database:
27 .   -drawaxis_hold - hold the initial set of axis limits for future plotting
28 
29     Level: advanced
30 
31 .seealso:  PetscDrawAxisSetHoldLimits()
32 
33 @*/
34 PetscErrorCode  PetscDrawAxisSetLimits(PetscDrawAxis axis,PetscReal xmin,PetscReal xmax,PetscReal ymin,PetscReal ymax)
35 {
36   PetscErrorCode ierr;
37 
38   PetscFunctionBegin;
39   if (!axis) PetscFunctionReturn(0);
40   if (axis->hold) PetscFunctionReturn(0);
41   axis->xlow = xmin;
42   axis->xhigh= xmax;
43   axis->ylow = ymin;
44   axis->yhigh= ymax;
45   ierr = PetscOptionsHasName(((PetscObject)axis)->prefix,"-drawaxis_hold",&axis->hold);CHKERRQ(ierr);
46   PetscFunctionReturn(0);
47 }
48 
49 #undef __FUNCT__
50 #define __FUNCT__ "PetscDrawAxisGetLimits"
51 /*@
52     PetscDrawAxisGetLimits -  Gets the limits (in user coords) of the axis
53 
54     Not Collective (ignored on all processors except processor 0 of PetscDrawAxis)
55 
56     Input Parameters:
57 +   axis - the axis
58 .   xmin,xmax - limits in x
59 -   ymin,ymax - limits in y
60 
61     Level: advanced
62 
63 .seealso:  PetscDrawAxisSetLimits()
64 
65 @*/
66 PetscErrorCode  PetscDrawAxisGetLimits(PetscDrawAxis axis,PetscReal *xmin,PetscReal *xmax,PetscReal *ymin,PetscReal *ymax)
67 {
68   PetscFunctionBegin;
69   if (!axis) PetscFunctionReturn(0);
70   if (axis->hold) PetscFunctionReturn(0);
71   *xmin = axis->xlow;
72   *xmax = axis->xhigh;
73   *ymin = axis->ylow;
74   *ymax = axis->yhigh;
75   PetscFunctionReturn(0);
76 }
77 
78 #undef __FUNCT__
79 #define __FUNCT__ "PetscADefLabel"
80 /*
81    val is the label value.  sep is the separation to the next (or previous)
82    label; this is useful in determining how many significant figures to
83    keep.
84  */
85 PetscErrorCode PetscADefLabel(PetscReal val,PetscReal sep,char **p)
86 {
87   static char    buf[40];
88   char           fmat[10];
89   PetscErrorCode ierr;
90   int            w,d;
91   PetscReal      rval;
92 
93   PetscFunctionBegin;
94   /* Find the string */
95   if (PetscAbsReal(val)/sep <  1.e-6) {
96     buf[0] = '0'; buf[1] = 0;
97   } else if (PetscAbsReal(val) < 1.0e6 && PetscAbsReal(val) > 1.e-4) {
98     /* Compute the number of digits */
99     w = 0;
100     d = 0;
101     if (sep > 0.0) {
102 	d = (int)ceil(- log10 (sep));
103 	if (d < 0) d = 0;
104 	if (PetscAbsReal(val) < 1.0e-6*sep) {
105 	    /* This is the case where we are near zero and less than a small
106 	       fraction of the sep.  In this case, we use 0 as the value */
107 	    val = 0.0;
108 	    w   = d;
109         }
110 	else if (val == 0.0) w   = d;
111 	else w = (int)(ceil(log10(PetscAbsReal(val))) + d);
112 	if (w < 1)   w ++;
113 	if (val < 0) w ++;
114     }
115 
116     ierr = PetscRint(val,&rval);CHKERRQ(ierr);
117     if (rval == val) {
118 	if (w > 0) sprintf(fmat,"%%%dd",w);
119 	else {ierr = PetscStrcpy(fmat,"%d");CHKERRQ(ierr);}
120 	sprintf(buf,fmat,(int)val);
121         ierr = PetscStripInitialZero(buf);CHKERRQ(ierr);
122         ierr = PetscStripAllZeros(buf);CHKERRQ(ierr);
123         ierr = PetscStripTrailingZeros(buf);CHKERRQ(ierr);
124     } else {
125 	/* The code used here is inappropriate for a val of 0, which
126 	   tends to print with an excessive numer of digits.  In this
127 	   case, we should look at the next/previous values and
128 	   use those widths */
129 	if (w > 0) sprintf(fmat,"%%%d.%dlf",w + 1,d);
130 	else {ierr = PetscStrcpy(fmat,"%lf");CHKERRQ(ierr);}
131 	sprintf(buf,fmat,(double)val);
132         ierr = PetscStripInitialZero(buf);CHKERRQ(ierr);
133         ierr = PetscStripAllZeros(buf);CHKERRQ(ierr);
134         ierr = PetscStripTrailingZeros(buf);CHKERRQ(ierr);
135     }
136   } else {
137     ierr = PetscSNPrintf(buf,40,"%g",(double)val);
138     /* remove the extraneous 0 before the e */
139     ierr = PetscStripZeros(buf);CHKERRQ(ierr);
140     ierr = PetscStripZerosPlus(buf);CHKERRQ(ierr);
141     ierr = PetscStripInitialZero(buf);CHKERRQ(ierr);
142     ierr = PetscStripAllZeros(buf);CHKERRQ(ierr);
143     ierr = PetscStripTrailingZeros(buf);CHKERRQ(ierr);
144   }
145   *p =buf;
146   PetscFunctionReturn(0);
147 }
148 
149 #undef __FUNCT__
150 #define __FUNCT__ "PetscADefTicks"
151 /* Finds "nice" locations for the ticks */
152 PetscErrorCode PetscADefTicks(PetscReal low,PetscReal high,int num,int *ntick,PetscReal * tickloc,int  maxtick)
153 {
154   PetscErrorCode ierr;
155   int            i,power;
156   PetscReal      x = 0.0,base=0.0;
157 
158   PetscFunctionBegin;
159   /* patch if low == high */
160   if (low == high) {
161     low  -= .01;
162     high += .01;
163   }
164 
165   /*  if (PetscAbsReal(low-high) < 1.e-8) {
166     low  -= .01;
167     high += .01;
168   } */
169 
170   ierr = PetscAGetBase(low,high,num,&base,&power);CHKERRQ(ierr);
171   ierr = PetscAGetNice(low,base,-1,&x);CHKERRQ(ierr);
172 
173   /* Values are of the form j * base */
174   /* Find the starting value */
175   if (x < low) x += base;
176 
177   i = 0;
178   while (i < maxtick && x <= high) {
179     tickloc[i++] = x;
180     x += base;
181   }
182   *ntick = i;
183 
184   if (i < 2 && num < 10) {
185     ierr = PetscADefTicks(low,high,num+1,ntick,tickloc,maxtick);CHKERRQ(ierr);
186   }
187   PetscFunctionReturn(0);
188 }
189 
190 #define EPS 1.e-6
191 
192 #undef __FUNCT__
193 #define __FUNCT__ "PetscExp10"
194 PetscErrorCode PetscExp10(PetscReal d,PetscReal *result)
195 {
196   PetscFunctionBegin;
197   *result = pow((PetscReal)10.0,d);
198   PetscFunctionReturn(0);
199 }
200 
201 #undef __FUNCT__
202 #define __FUNCT__ "PetscMod"
203 PetscErrorCode PetscMod(PetscReal x,PetscReal y,PetscReal *result)
204 {
205   int     i;
206 
207   PetscFunctionBegin;
208   if (y == 1) {
209     *result = 0.0;
210     PetscFunctionReturn(0);
211   }
212   i   = ((int)x) / ((int)y);
213   x   = x - i * y;
214   while (x > y) x -= y;
215   *result = x;
216   PetscFunctionReturn(0);
217 }
218 
219 #undef __FUNCT__
220 #define __FUNCT__ "PetscCopysign"
221 PetscErrorCode PetscCopysign(PetscReal a,PetscReal b,PetscReal *result)
222 {
223   PetscFunctionBegin;
224   if (b >= 0) *result = a;
225   else        *result = -a;
226   PetscFunctionReturn(0);
227 }
228 
229 #undef __FUNCT__
230 #define __FUNCT__ "PetscAGetNice"
231 /*
232     Given a value "in" and a "base", return a nice value.
233     based on "sign", extend up (+1) or down (-1)
234  */
235 PetscErrorCode PetscAGetNice(PetscReal in,PetscReal base,int sign,PetscReal *result)
236 {
237   PetscReal      etmp,s,s2,m;
238   PetscErrorCode ierr;
239 
240   PetscFunctionBegin;
241   ierr    = PetscCopysign (0.5,(double)sign,&s);CHKERRQ(ierr);
242   etmp    = in / base + 0.5 + s;
243   ierr    = PetscCopysign (0.5,etmp,&s);CHKERRQ(ierr);
244   ierr    = PetscCopysign (EPS * etmp,(double)sign,&s2);CHKERRQ(ierr);
245   etmp    = etmp - 0.5 + s - s2;
246   ierr    = PetscMod(etmp,1.0,&m);CHKERRQ(ierr);
247   etmp    = base * (etmp -  m);
248   *result = etmp;
249   PetscFunctionReturn(0);
250 }
251 
252 #undef __FUNCT__
253 #define __FUNCT__ "PetscAGetBase"
254 PetscErrorCode PetscAGetBase(PetscReal vmin,PetscReal vmax,int num,PetscReal*Base,int*power)
255 {
256   PetscReal        base,ftemp,e10;
257   static PetscReal base_try[5] = {10.0,5.0,2.0,1.0,0.5};
258   PetscErrorCode   ierr;
259   int              i;
260 
261   PetscFunctionBegin;
262   /* labels of the form n * BASE */
263   /* get an approximate value for BASE */
264   base    = (vmax - vmin) / (double)(num + 1);
265 
266   /* make it of form   m x 10^power,  m in [1.0, 10) */
267   if (base <= 0.0) {
268     base    = PetscAbsReal(vmin);
269     if (base < 1.0) base = 1.0;
270   }
271   ftemp   = log10((1.0 + EPS) * base);
272   if (ftemp < 0.0)  ftemp   -= 1.0;
273   *power  = (int)ftemp;
274   ierr = PetscExp10((double)- *power,&e10);CHKERRQ(ierr);
275   base    = base * e10;
276   if (base < 1.0) base    = 1.0;
277   /* now reduce it to one of 1, 2, or 5 */
278   for (i=1; i<5; i++) {
279     if (base >= base_try[i]) {
280       ierr = PetscExp10((double)*power,&e10);CHKERRQ(ierr);
281       base = base_try[i-1] * e10;
282       if (i == 1) *power    = *power + 1;
283       break;
284     }
285   }
286   *Base   = base;
287   PetscFunctionReturn(0);
288 }
289 
290 
291 
292 
293 
294 
295