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