xref: /petsc/src/sys/classes/draw/utils/axis.c (revision db05f41b88540d61f4bd88b8a8012f1ff01b70f8)
15c6c1daeSBarry Smith 
25c6c1daeSBarry Smith #include <../src/sys/classes/draw/utils/axisimpl.h>
35c6c1daeSBarry Smith 
45c6c1daeSBarry Smith #undef __FUNCT__
55c6c1daeSBarry Smith #define __FUNCT__ "PetscRint"
65c6c1daeSBarry Smith static PetscErrorCode PetscRint(PetscReal x,PetscReal *result)
75c6c1daeSBarry Smith {
85c6c1daeSBarry Smith   PetscFunctionBegin;
95c6c1daeSBarry Smith   if (x > 0) *result = floor(x + 0.5);
105c6c1daeSBarry Smith   else       *result = floor(x - 0.5);
115c6c1daeSBarry Smith   PetscFunctionReturn(0);
125c6c1daeSBarry Smith }
135c6c1daeSBarry Smith 
145c6c1daeSBarry Smith #undef __FUNCT__
155c6c1daeSBarry Smith #define __FUNCT__ "PetscDrawAxisSetLimits"
165c6c1daeSBarry Smith /*@
175c6c1daeSBarry Smith     PetscDrawAxisSetLimits -  Sets the limits (in user coords) of the axis
185c6c1daeSBarry Smith 
195c6c1daeSBarry Smith     Not Collective (ignored on all processors except processor 0 of PetscDrawAxis)
205c6c1daeSBarry Smith 
215c6c1daeSBarry Smith     Input Parameters:
225c6c1daeSBarry Smith +   axis - the axis
235c6c1daeSBarry Smith .   xmin,xmax - limits in x
245c6c1daeSBarry Smith -   ymin,ymax - limits in y
255c6c1daeSBarry Smith 
261c059eddSBarry Smith     Options Database:
271c059eddSBarry Smith .   -drawaxis_hold - hold the initial set of axis limits for future plotting
281c059eddSBarry Smith 
295c6c1daeSBarry Smith     Level: advanced
305c6c1daeSBarry Smith 
315c6c1daeSBarry Smith .seealso:  PetscDrawAxisSetHoldLimits()
325c6c1daeSBarry Smith 
335c6c1daeSBarry Smith @*/
345c6c1daeSBarry Smith PetscErrorCode  PetscDrawAxisSetLimits(PetscDrawAxis axis,PetscReal xmin,PetscReal xmax,PetscReal ymin,PetscReal ymax)
355c6c1daeSBarry Smith {
361c059eddSBarry Smith   PetscErrorCode ierr;
371c059eddSBarry Smith 
385c6c1daeSBarry Smith   PetscFunctionBegin;
395c6c1daeSBarry Smith   if (!axis) PetscFunctionReturn(0);
405c6c1daeSBarry Smith   if (axis->hold) PetscFunctionReturn(0);
415c6c1daeSBarry Smith   axis->xlow = xmin;
425c6c1daeSBarry Smith   axis->xhigh= xmax;
435c6c1daeSBarry Smith   axis->ylow = ymin;
445c6c1daeSBarry Smith   axis->yhigh= ymax;
451c059eddSBarry Smith   ierr = PetscOptionsHasName(((PetscObject)axis)->prefix,"-drawaxis_hold",&axis->hold);CHKERRQ(ierr);
465c6c1daeSBarry Smith   PetscFunctionReturn(0);
475c6c1daeSBarry Smith }
485c6c1daeSBarry Smith 
495c6c1daeSBarry Smith #undef __FUNCT__
505c6c1daeSBarry Smith #define __FUNCT__ "PetscDrawAxisGetLimits"
515c6c1daeSBarry Smith /*@
525c6c1daeSBarry Smith     PetscDrawAxisGetLimits -  Gets the limits (in user coords) of the axis
535c6c1daeSBarry Smith 
545c6c1daeSBarry Smith     Not Collective (ignored on all processors except processor 0 of PetscDrawAxis)
555c6c1daeSBarry Smith 
565c6c1daeSBarry Smith     Input Parameters:
575c6c1daeSBarry Smith +   axis - the axis
585c6c1daeSBarry Smith .   xmin,xmax - limits in x
595c6c1daeSBarry Smith -   ymin,ymax - limits in y
605c6c1daeSBarry Smith 
615c6c1daeSBarry Smith     Level: advanced
625c6c1daeSBarry Smith 
635c6c1daeSBarry Smith .seealso:  PetscDrawAxisSetLimits()
645c6c1daeSBarry Smith 
655c6c1daeSBarry Smith @*/
665c6c1daeSBarry Smith PetscErrorCode  PetscDrawAxisGetLimits(PetscDrawAxis axis,PetscReal *xmin,PetscReal *xmax,PetscReal *ymin,PetscReal *ymax)
675c6c1daeSBarry Smith {
685c6c1daeSBarry Smith   PetscFunctionBegin;
695c6c1daeSBarry Smith   if (!axis) PetscFunctionReturn(0);
705c6c1daeSBarry Smith   if (axis->hold) PetscFunctionReturn(0);
715c6c1daeSBarry Smith   *xmin = axis->xlow;
725c6c1daeSBarry Smith   *xmax = axis->xhigh;
735c6c1daeSBarry Smith   *ymin = axis->ylow;
745c6c1daeSBarry Smith   *ymax = axis->yhigh;
755c6c1daeSBarry Smith   PetscFunctionReturn(0);
765c6c1daeSBarry Smith }
775c6c1daeSBarry Smith 
785c6c1daeSBarry Smith #undef __FUNCT__
795c6c1daeSBarry Smith #define __FUNCT__ "PetscADefLabel"
805c6c1daeSBarry Smith /*
815c6c1daeSBarry Smith    val is the label value.  sep is the separation to the next (or previous)
825c6c1daeSBarry Smith    label; this is useful in determining how many significant figures to
835c6c1daeSBarry Smith    keep.
845c6c1daeSBarry Smith  */
855c6c1daeSBarry Smith PetscErrorCode PetscADefLabel(PetscReal val,PetscReal sep,char **p)
865c6c1daeSBarry Smith {
875c6c1daeSBarry Smith   static char    buf[40];
885c6c1daeSBarry Smith   char           fmat[10];
895c6c1daeSBarry Smith   PetscErrorCode ierr;
905c6c1daeSBarry Smith   int            w,d;
915c6c1daeSBarry Smith   PetscReal      rval;
925c6c1daeSBarry Smith 
935c6c1daeSBarry Smith   PetscFunctionBegin;
945c6c1daeSBarry Smith   /* Find the string */
95ba129bcfSBarry Smith   if (PetscAbsReal(val)/sep <  1.e-4) {
965c6c1daeSBarry Smith     buf[0] = '0'; buf[1] = 0;
975c6c1daeSBarry Smith   } else if (PetscAbsReal(val) < 1.0e6 && PetscAbsReal(val) > 1.e-4) {
985c6c1daeSBarry Smith     /* Compute the number of digits */
995c6c1daeSBarry Smith     w = 0;
1005c6c1daeSBarry Smith     d = 0;
1015c6c1daeSBarry Smith     if (sep > 0.0) {
1025c6c1daeSBarry Smith 	d = (int)ceil(- log10 (sep));
1035c6c1daeSBarry Smith 	if (d < 0) d = 0;
1045c6c1daeSBarry Smith 	if (PetscAbsReal(val) < 1.0e-6*sep) {
1055c6c1daeSBarry Smith 	    /* This is the case where we are near zero and less than a small
1065c6c1daeSBarry Smith 	       fraction of the sep.  In this case, we use 0 as the value */
1075c6c1daeSBarry Smith 	    val = 0.0;
1085c6c1daeSBarry Smith 	    w   = d;
1095c6c1daeSBarry Smith         }
1105c6c1daeSBarry Smith 	else if (val == 0.0) w   = d;
1115c6c1daeSBarry Smith 	else w = (int)(ceil(log10(PetscAbsReal(val))) + d);
1125c6c1daeSBarry Smith 	if (w < 1)   w ++;
1135c6c1daeSBarry Smith 	if (val < 0) w ++;
1145c6c1daeSBarry Smith     }
1155c6c1daeSBarry Smith 
1165c6c1daeSBarry Smith     ierr = PetscRint(val,&rval);CHKERRQ(ierr);
1175c6c1daeSBarry Smith     if (rval == val) {
1185c6c1daeSBarry Smith 	if (w > 0) sprintf(fmat,"%%%dd",w);
1195c6c1daeSBarry Smith 	else {ierr = PetscStrcpy(fmat,"%d");CHKERRQ(ierr);}
1205c6c1daeSBarry Smith 	sprintf(buf,fmat,(int)val);
1215c6c1daeSBarry Smith         ierr = PetscStripInitialZero(buf);CHKERRQ(ierr);
1225c6c1daeSBarry Smith         ierr = PetscStripAllZeros(buf);CHKERRQ(ierr);
1235c6c1daeSBarry Smith         ierr = PetscStripTrailingZeros(buf);CHKERRQ(ierr);
1245c6c1daeSBarry Smith     } else {
1255c6c1daeSBarry Smith 	/* The code used here is inappropriate for a val of 0, which
1265c6c1daeSBarry Smith 	   tends to print with an excessive numer of digits.  In this
1275c6c1daeSBarry Smith 	   case, we should look at the next/previous values and
1285c6c1daeSBarry Smith 	   use those widths */
1295c6c1daeSBarry Smith 	if (w > 0) sprintf(fmat,"%%%d.%dlf",w + 1,d);
1305c6c1daeSBarry Smith 	else {ierr = PetscStrcpy(fmat,"%lf");CHKERRQ(ierr);}
1315c6c1daeSBarry Smith 	sprintf(buf,fmat,(double)val);
1325c6c1daeSBarry Smith         ierr = PetscStripInitialZero(buf);CHKERRQ(ierr);
1335c6c1daeSBarry Smith         ierr = PetscStripAllZeros(buf);CHKERRQ(ierr);
1345c6c1daeSBarry Smith         ierr = PetscStripTrailingZeros(buf);CHKERRQ(ierr);
1355c6c1daeSBarry Smith     }
1365c6c1daeSBarry Smith   } else {
1375c6c1daeSBarry Smith     ierr = PetscSNPrintf(buf,40,"%g",(double)val);
1385c6c1daeSBarry Smith     /* remove the extraneous 0 before the e */
1395c6c1daeSBarry Smith     ierr = PetscStripZeros(buf);CHKERRQ(ierr);
1405c6c1daeSBarry Smith     ierr = PetscStripZerosPlus(buf);CHKERRQ(ierr);
1415c6c1daeSBarry Smith     ierr = PetscStripInitialZero(buf);CHKERRQ(ierr);
1425c6c1daeSBarry Smith     ierr = PetscStripAllZeros(buf);CHKERRQ(ierr);
1435c6c1daeSBarry Smith     ierr = PetscStripTrailingZeros(buf);CHKERRQ(ierr);
1445c6c1daeSBarry Smith   }
1455c6c1daeSBarry Smith   *p =buf;
1465c6c1daeSBarry Smith   PetscFunctionReturn(0);
1475c6c1daeSBarry Smith }
1485c6c1daeSBarry Smith 
1495c6c1daeSBarry Smith #undef __FUNCT__
1505c6c1daeSBarry Smith #define __FUNCT__ "PetscADefTicks"
1515c6c1daeSBarry Smith /* Finds "nice" locations for the ticks */
1525c6c1daeSBarry Smith PetscErrorCode PetscADefTicks(PetscReal low,PetscReal high,int num,int *ntick,PetscReal * tickloc,int  maxtick)
1535c6c1daeSBarry Smith {
1545c6c1daeSBarry Smith   PetscErrorCode ierr;
1555c6c1daeSBarry Smith   int            i,power;
1565c6c1daeSBarry Smith   PetscReal      x = 0.0,base=0.0;
1575c6c1daeSBarry Smith 
1585c6c1daeSBarry Smith   PetscFunctionBegin;
1595c6c1daeSBarry Smith   /* patch if low == high */
1605c6c1daeSBarry Smith   if (low == high) {
1615c6c1daeSBarry Smith     low  -= .01;
1625c6c1daeSBarry Smith     high += .01;
1635c6c1daeSBarry Smith   }
1645c6c1daeSBarry Smith 
1655c6c1daeSBarry Smith   /*  if (PetscAbsReal(low-high) < 1.e-8) {
1665c6c1daeSBarry Smith     low  -= .01;
1675c6c1daeSBarry Smith     high += .01;
1685c6c1daeSBarry Smith   } */
1695c6c1daeSBarry Smith 
1705c6c1daeSBarry Smith   ierr = PetscAGetBase(low,high,num,&base,&power);CHKERRQ(ierr);
1715c6c1daeSBarry Smith   ierr = PetscAGetNice(low,base,-1,&x);CHKERRQ(ierr);
1725c6c1daeSBarry Smith 
1735c6c1daeSBarry Smith   /* Values are of the form j * base */
1745c6c1daeSBarry Smith   /* Find the starting value */
1755c6c1daeSBarry Smith   if (x < low) x += base;
1765c6c1daeSBarry Smith 
1775c6c1daeSBarry Smith   i = 0;
1785c6c1daeSBarry Smith   while (i < maxtick && x <= high) {
1795c6c1daeSBarry Smith     tickloc[i++] = x;
1805c6c1daeSBarry Smith     x += base;
1815c6c1daeSBarry Smith   }
1825c6c1daeSBarry Smith   *ntick = i;
1835c6c1daeSBarry Smith 
1845c6c1daeSBarry Smith   if (i < 2 && num < 10) {
1855c6c1daeSBarry Smith     ierr = PetscADefTicks(low,high,num+1,ntick,tickloc,maxtick);CHKERRQ(ierr);
1865c6c1daeSBarry Smith   }
187*db05f41bSBarry Smith   if (num == 10) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"trouble");
1885c6c1daeSBarry Smith   PetscFunctionReturn(0);
1895c6c1daeSBarry Smith }
1905c6c1daeSBarry Smith 
1915c6c1daeSBarry Smith #define EPS 1.e-6
1925c6c1daeSBarry Smith 
1935c6c1daeSBarry Smith #undef __FUNCT__
1945c6c1daeSBarry Smith #define __FUNCT__ "PetscExp10"
1955c6c1daeSBarry Smith PetscErrorCode PetscExp10(PetscReal d,PetscReal *result)
1965c6c1daeSBarry Smith {
1975c6c1daeSBarry Smith   PetscFunctionBegin;
1985c6c1daeSBarry Smith   *result = pow((PetscReal)10.0,d);
1995c6c1daeSBarry Smith   PetscFunctionReturn(0);
2005c6c1daeSBarry Smith }
2015c6c1daeSBarry Smith 
2025c6c1daeSBarry Smith #undef __FUNCT__
2035c6c1daeSBarry Smith #define __FUNCT__ "PetscMod"
2045c6c1daeSBarry Smith PetscErrorCode PetscMod(PetscReal x,PetscReal y,PetscReal *result)
2055c6c1daeSBarry Smith {
2065c6c1daeSBarry Smith   int     i;
2075c6c1daeSBarry Smith 
2085c6c1daeSBarry Smith   PetscFunctionBegin;
2095c6c1daeSBarry Smith   if (y == 1) {
2105c6c1daeSBarry Smith     *result = 0.0;
2115c6c1daeSBarry Smith     PetscFunctionReturn(0);
2125c6c1daeSBarry Smith   }
2135c6c1daeSBarry Smith   i   = ((int)x) / ((int)y);
2145c6c1daeSBarry Smith   x   = x - i * y;
2155c6c1daeSBarry Smith   while (x > y) x -= y;
2165c6c1daeSBarry Smith   *result = x;
2175c6c1daeSBarry Smith   PetscFunctionReturn(0);
2185c6c1daeSBarry Smith }
2195c6c1daeSBarry Smith 
2205c6c1daeSBarry Smith #undef __FUNCT__
2215c6c1daeSBarry Smith #define __FUNCT__ "PetscCopysign"
2225c6c1daeSBarry Smith PetscErrorCode PetscCopysign(PetscReal a,PetscReal b,PetscReal *result)
2235c6c1daeSBarry Smith {
2245c6c1daeSBarry Smith   PetscFunctionBegin;
2255c6c1daeSBarry Smith   if (b >= 0) *result = a;
2265c6c1daeSBarry Smith   else        *result = -a;
2275c6c1daeSBarry Smith   PetscFunctionReturn(0);
2285c6c1daeSBarry Smith }
2295c6c1daeSBarry Smith 
2305c6c1daeSBarry Smith #undef __FUNCT__
2315c6c1daeSBarry Smith #define __FUNCT__ "PetscAGetNice"
2325c6c1daeSBarry Smith /*
2335c6c1daeSBarry Smith     Given a value "in" and a "base", return a nice value.
2345c6c1daeSBarry Smith     based on "sign", extend up (+1) or down (-1)
2355c6c1daeSBarry Smith  */
2365c6c1daeSBarry Smith PetscErrorCode PetscAGetNice(PetscReal in,PetscReal base,int sign,PetscReal *result)
2375c6c1daeSBarry Smith {
2385c6c1daeSBarry Smith   PetscReal      etmp,s,s2,m;
2395c6c1daeSBarry Smith   PetscErrorCode ierr;
2405c6c1daeSBarry Smith 
2415c6c1daeSBarry Smith   PetscFunctionBegin;
2425c6c1daeSBarry Smith   ierr    = PetscCopysign (0.5,(double)sign,&s);CHKERRQ(ierr);
2435c6c1daeSBarry Smith   etmp    = in / base + 0.5 + s;
2445c6c1daeSBarry Smith   ierr    = PetscCopysign (0.5,etmp,&s);CHKERRQ(ierr);
2455c6c1daeSBarry Smith   ierr    = PetscCopysign (EPS * etmp,(double)sign,&s2);CHKERRQ(ierr);
2465c6c1daeSBarry Smith   etmp    = etmp - 0.5 + s - s2;
2475c6c1daeSBarry Smith   ierr    = PetscMod(etmp,1.0,&m);CHKERRQ(ierr);
2485c6c1daeSBarry Smith   etmp    = base * (etmp -  m);
2495c6c1daeSBarry Smith   *result = etmp;
2505c6c1daeSBarry Smith   PetscFunctionReturn(0);
2515c6c1daeSBarry Smith }
2525c6c1daeSBarry Smith 
2535c6c1daeSBarry Smith #undef __FUNCT__
2545c6c1daeSBarry Smith #define __FUNCT__ "PetscAGetBase"
2555c6c1daeSBarry Smith PetscErrorCode PetscAGetBase(PetscReal vmin,PetscReal vmax,int num,PetscReal*Base,int*power)
2565c6c1daeSBarry Smith {
2575c6c1daeSBarry Smith   PetscReal        base,ftemp,e10;
2585c6c1daeSBarry Smith   static PetscReal base_try[5] = {10.0,5.0,2.0,1.0,0.5};
2595c6c1daeSBarry Smith   PetscErrorCode   ierr;
2605c6c1daeSBarry Smith   int              i;
2615c6c1daeSBarry Smith 
2625c6c1daeSBarry Smith   PetscFunctionBegin;
2635c6c1daeSBarry Smith   /* labels of the form n * BASE */
2645c6c1daeSBarry Smith   /* get an approximate value for BASE */
2655c6c1daeSBarry Smith   base    = (vmax - vmin) / (double)(num + 1);
2665c6c1daeSBarry Smith 
2675c6c1daeSBarry Smith   /* make it of form   m x 10^power,  m in [1.0, 10) */
2685c6c1daeSBarry Smith   if (base <= 0.0) {
2695c6c1daeSBarry Smith     base    = PetscAbsReal(vmin);
2705c6c1daeSBarry Smith     if (base < 1.0) base = 1.0;
2715c6c1daeSBarry Smith   }
2725c6c1daeSBarry Smith   ftemp   = log10((1.0 + EPS) * base);
2735c6c1daeSBarry Smith   if (ftemp < 0.0)  ftemp   -= 1.0;
2745c6c1daeSBarry Smith   *power  = (int)ftemp;
2755c6c1daeSBarry Smith   ierr = PetscExp10((double)- *power,&e10);CHKERRQ(ierr);
2765c6c1daeSBarry Smith   base    = base * e10;
2775c6c1daeSBarry Smith   if (base < 1.0) base    = 1.0;
2785c6c1daeSBarry Smith   /* now reduce it to one of 1, 2, or 5 */
2795c6c1daeSBarry Smith   for (i=1; i<5; i++) {
2805c6c1daeSBarry Smith     if (base >= base_try[i]) {
2815c6c1daeSBarry Smith       ierr = PetscExp10((double)*power,&e10);CHKERRQ(ierr);
2825c6c1daeSBarry Smith       base = base_try[i-1] * e10;
2835c6c1daeSBarry Smith       if (i == 1) *power    = *power + 1;
2845c6c1daeSBarry Smith       break;
2855c6c1daeSBarry Smith     }
2865c6c1daeSBarry Smith   }
2875c6c1daeSBarry Smith   *Base   = base;
2885c6c1daeSBarry Smith   PetscFunctionReturn(0);
2895c6c1daeSBarry Smith }
2905c6c1daeSBarry Smith 
2915c6c1daeSBarry Smith 
2925c6c1daeSBarry Smith 
2935c6c1daeSBarry Smith 
2945c6c1daeSBarry Smith 
2955c6c1daeSBarry Smith 
296