File: pretty.src.js

package info (click to toggle)
rgl 1.3.34-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 13,968 kB
  • sloc: cpp: 23,234; ansic: 7,462; javascript: 6,125; sh: 3,555; makefile: 2
file content (163 lines) | stat: -rw-r--r-- 6,006 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/**
 * Pretty function from R
 * @name ___PRETTY_FROM_R___
 * @memberof rglwidgetClass
 * @kind function
 * @instance
 */


/* This file is translated from pretty.c, which was
 taken from the R sources, r61744 of src/appl/pretty.c,
 with minimal changes */

/*
 *  R : A Computer Language for Statistical Data Analysis
 *  Copyright (C) 1995-2012  The R Core Team
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, a copy is available at
 *  http://www.r-project.org/Licenses/
 */

/**     
 * Construct pretty values to cover an interval
 * @param { number } lo - lower end of interval
 * @param { number } up - upper end of interval
 * @param { number } ndiv - requested number of divisions
 * @param { number } min_n - minimum divisions
 * @param { number } shrink_sml - if too many cells, amount to shrink by
 * @param { number } high_u_fact - bias in favour of larger units
 * @param { number } eps_correction - correction to bounds
 * @param { Boolean } return_bounds - whether to return bounds
 * @description
 * Pretty Intervals

 * Constructs m "pretty" values which cover the given interval	*lo <= *up
 *	m ~= *ndiv + 1	(i.e., ndiv := approximate number of INTERVALS)
 *
 * It is not quite clear what should happen for	 *lo = *up;
 * S itself behaves quite funilly, then.
 *
 * In my opinion, a proper 'pretty' should always ensure
 * *lo < *up, and hence *ndiv >=1 in the result.
 * However, in S and here, we allow  *lo == *up, and *ndiv = 0.
 * Note however, that we are NOT COMPATIBLE to S. [Martin M.]
 *
 * NEW (0.63.2): ns, nu are double (==> no danger of integer overflow)
 *
 * We determine
 * if the interval (up - lo) is ``small'' [<==>	 i_small == TRUE, below].
 * For the ``i_small'' situation, there is a parameter  shrink_sml,
 * the factor by which the "scale" is shrunk.		~~~~~~~~~~
 * It is advisable to set it to some (smaller) integer power of 2,
 * since this enables exact floating point division.
 */
rglwidgetClass.prototype.R_pretty = function(
  lo, up, ndiv, min_n, shrink_sml, high_u_fact,
  eps_correction, return_bounds) {
  /* From version 0.65 on, we had rounding_eps := 1e-5, before, r..eps = 0
   * 1e-7 is consistent with seq.default() */
  var rounding_eps = 1e-7,  h = high_u_fact[0],
                                           h5 = high_u_fact[1], 
                                                           dx, cell, unit, base, U, ns, nu, k, i_small,
                                                           DBL_EPSILON = Number.EPSILON,
                                                           DBL_MIN = Number.MIN_VALUE,
                                                           DBL_MAX = Number.MAX_VALUE;
  
  dx = up - lo;
  /* cell := "scale"	here */
  if (dx === 0 && up === 0) { /*  up == lo == 0	 */
  cell = 1;
    i_small = true;
  } else {
    cell = Math.max(Math.abs(lo), Math.abs(up));
    /* U = upper bound on cell/unit */
    U = (1 + (h5 >= 1.5*h+0.5)) ? 1/(1+h) : 1.5/(1+h5);
    /* added times 3, as several calculations here */
    i_small = dx < cell * U * Math.max(1,ndiv) * DBL_EPSILON *3;
  }
  
  /*OLD: cell = FLT_EPSILON+ dx / *ndiv; FLT_EPSILON = 1.192e-07 */
  if(i_small) {
    if(cell > 10)
      cell = 9 + cell/10;
    cell *= shrink_sml;
    if(min_n > 1) cell /= min_n;
  } else {
    cell = dx;
    if(ndiv > 1) cell /= ndiv;
  }
  
  if(cell < 20*DBL_MIN) {
    /* warning(_("Internal(pretty()): very small range.. corrected")); */
    cell = 20*DBL_MIN;
  } else if(cell * 10 > DBL_MAX) {
    /* warning(_("Internal(pretty()): very large range.. corrected")); */
    cell = 0.1*DBL_MAX;
  }
  base = Math.pow(10, Math.floor(Math.log10(cell))); /* base <= cell < 10*base */
    
    /* unit : from { 1,2,5,10 } * base
     *	 such that |u - cell| is small,
     * favoring larger (if h > 1, else smaller)  u  values;
     * favor '5' more than '2'  if h5 > h  (default h5 = .5 + 1.5 h) */
    unit = base;
    if((U = 2*base)-cell <  h*(cell-unit)) { unit = U;
      if((U = 5*base)-cell < h5*(cell-unit)) { unit = U;
        if((U =10*base)-cell <  h*(cell-unit)) unit = U; }}
    /* Result: c := cell,  u := unit,  b := base
     *	c in [	1,	      (2+ h) /(1+h) ] b ==> u=  b
     *	c in ( (2+ h)/(1+h),  (5+2h5)/(1+h5)] b ==> u= 2b
     *	c in ( (5+2h)/(1+h), (10+5h) /(1+h) ] b ==> u= 5b
     *	c in ((10+5h)/(1+h),	         10 ) b ==> u=10b
     *
     *	===>	2/5 *(2+h)/(1+h)  <=  c/u  <=  (2+h)/(1+h)	*/
    
    ns = Math.floor(lo/unit+rounding_eps);
    nu = Math.ceil (up/unit-rounding_eps);
    
    if(eps_correction && (eps_correction > 1 || !i_small)) {
      if(lo !== 0.0) lo *= (1- DBL_EPSILON); else lo = -DBL_MIN;
      if(up !== 0.0) up *= (1+ DBL_EPSILON); else up = +DBL_MIN;
    }
    
    while(ns*unit > lo + rounding_eps*unit) ns--;
    
    while(nu*unit < up - rounding_eps*unit) nu++;
    
    k = Math.floor(0.5 + nu - ns);
    if(k < min_n) {
      /* ensure that	nu - ns	 == min_n */
      
      k = min_n - k;
      if(ns >= 0) {
        nu += k/2;
        ns -= k/2 + k%2;/* ==> nu-ns = old(nu-ns) + min_n -k = min_n */
      } else {
        ns -= k/2;
        nu += k/2 + k%2;
      }
      ndiv = min_n;
    } else {
      ndiv = k;
    }
    if(return_bounds) { /* if()'s to ensure that result covers original range */
      if(ns * unit < lo) lo = ns * unit;
      if(nu * unit > up) up = nu * unit;
    } else {
      lo = ns;
      up = nu;
    }
    return {lo:lo, up:up, ndiv:ndiv, unit:unit};
};