scirenderer: bound iteration Graduation
[scilab.git] / scilab / modules / scirenderer / src / org / scilab / forge / scirenderer / ruler / graduations / LinearGraduations.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
4  * Copyright (C) 2013 - Scilab Enterprises - Calixte DENIZET
5  *
6  * Copyright (C) 2012 - 2016 - Scilab Enterprises
7  *
8  * This file is hereby licensed under the terms of the GNU GPL v2.0,
9  * pursuant to article 5.3.4 of the CeCILL v.2.1.
10  * This file was originally licensed under the terms of the CeCILL v2.1,
11  * and continues to be available under such terms.
12  * For more information, see the COPYING file which you should have received
13  * along with this program.
14  */
15
16 package org.scilab.forge.scirenderer.ruler.graduations;
17
18 import java.util.ArrayList;
19 import java.util.List;
20
21 /**
22  * A linear graduation is a graduation with regular spaces mark.
23  * The mark distance is called "Step" and have for value {@code mantissa x 10^exponent}.
24  * Where mantissa is 1, 2 or 5.
25  * Exponent is an integer.
26  *
27  * @author Pierre Lando
28  */
29 public final class LinearGraduations extends AbstractGraduations implements Graduations {
30
31     /**
32      * The step exponent.
33      */
34     protected final int stepExponent;
35
36     /**
37      * The step mantissa.
38      */
39     protected final int stepMantissa;
40
41     private LinearGraduations moreGraduation;
42     private LinearGraduations alternativeGraduation;
43     private Graduations subGraduation;
44     private Double stepValue;
45     private List<Double> allValues;
46     private List<Double> newValues;
47
48     /**
49      * Private constructor.
50      * Use creates methods.
51      */
52     private LinearGraduations() {
53         super(null);
54         stepExponent = 0;
55         stepMantissa = 0;
56     }
57
58     private LinearGraduations(Graduations parentGraduations, int stepExponent, int stepMantissa) {
59         super(parentGraduations);
60         this.stepExponent = stepExponent;
61         this.stepMantissa = stepMantissa;
62     }
63
64     private LinearGraduations(Graduations parentGraduations, double lowerBound, boolean lowerBoundIncluded, double upperBound, boolean upperBoundIncluded) {
65         super(parentGraduations, lowerBound, lowerBoundIncluded, upperBound, upperBoundIncluded);
66         if (lowerBound != upperBound) {
67             double size = upperBound - lowerBound;
68             stepExponent = (int) Math.ceil(Math.log10(size));
69             stepMantissa = 1;
70         } else {
71             stepExponent = 0;
72             stepMantissa = 0;
73             newValues = new ArrayList<Double>();
74             allValues = new ArrayList<Double>();
75             allValues.add(lowerBound);
76         }
77     }
78
79     public static LinearGraduations create(double lowerBound, double upperBound) {
80         return create(lowerBound, true, upperBound, true);
81     }
82
83     public static LinearGraduations create(
84         Graduations parentGraduations,
85         double lowerBound, boolean lowerBoundIncluded,
86         double upperBound, boolean upperBoundIncluded
87     ) {
88         if (lowerBound < upperBound) {
89             return new LinearGraduations(parentGraduations, lowerBound, lowerBoundIncluded, upperBound, upperBoundIncluded);
90         } else {
91             return new LinearGraduations(parentGraduations, upperBound, upperBoundIncluded, lowerBound, lowerBoundIncluded);
92         }
93     }
94
95     public static LinearGraduations create(double lowerBound, boolean lowerBoundIncluded, double upperBound, boolean upperBoundIncluded) {
96         if (lowerBound < upperBound) {
97             return new LinearGraduations(null, lowerBound, lowerBoundIncluded, upperBound, upperBoundIncluded);
98         } else {
99             return new LinearGraduations(null, upperBound, upperBoundIncluded, lowerBound, lowerBoundIncluded);
100         }
101     }
102
103
104     private static final double mypow10(int e) {
105         double p = 10;
106         double r = 1;
107         final boolean signed = e < 0;
108         if (signed) {
109             e = -e;
110         }
111         while (e != 0) {
112             if ((e & 1) != 0) {
113                 r *= p;
114             }
115             p *= p;
116             e >>= 1;
117         }
118
119         return signed ? 1 / r : r;
120     }
121
122     private static final long myceil(double x) {
123         if (x == 0) {
124             return 0L;
125         }
126
127         double r = Math.round(x);
128         if (Math.abs(1 - r / x) <= PRECISION) {
129             return (long) r;
130         }
131
132         return (long) Math.ceil(x);
133     }
134
135     private Double getStepValue() {
136         if (stepValue == null) {
137             if (stepMantissa == 1) {
138                 stepValue = mypow10(stepExponent);
139             } else {
140                 stepValue = stepMantissa * mypow10(stepExponent);
141             }
142         }
143         return stepValue;
144     }
145
146     private final long getIndex(double x) {
147         switch (stepMantissa) {
148             case 1:
149                 return myceil(mypow10(-stepExponent) * x);
150             case 2:
151                 return myceil(5 * mypow10(-stepExponent - 1) * x);
152             case 5:
153                 return myceil(mypow10(-stepExponent - 1) * x * 2);
154             default:
155                 return myceil(mypow10(-stepExponent) * x / stepMantissa);
156         }
157     }
158
159     private boolean isNewIndex(final long index) {
160         /* We are now searching for value look like
161          * index * (stepMantissa * 10^n) and we don't want (previousStrepMantissa * 10^k) value.
162          */
163
164         switch (stepMantissa) {
165             case 1:
166                 // (5 * index * stepMantissa) % 10 != 0
167                 return (index % 2) != 0;
168             case 2:
169                 // (2 * index * stepMantissa) % 10 != 0
170                 return (index % 5) != 0;
171             default:
172                 // (5 * index * stepMantissa) % 10 != 0
173                 return ((index * stepMantissa) % 2) != 0;
174         }
175     }
176     
177     private final boolean canAdd(List<Double> container)
178     {
179         return container.size() < MAX_NUMBER_OF_GRADUATION;
180     }
181
182     @Override
183     public List<Double> getNewValues() {
184         if (getParentGraduations() == null) {
185             return getAllValues();
186         }
187
188         if (newValues == null) {
189             newValues = new ArrayList<Double>();
190             final double lb = getLowerBound();
191
192             long currentIndex = getIndex(lb);
193             double currentValue = getStepValue() * currentIndex;
194             double value = currentValue - lb;
195
196             if (value == 0 && !containRelative(value)) {
197                 value += getStepValue();
198                 currentIndex++;
199             }
200
201             while (canAdd(newValues) && containRelative(value) && !Double.isInfinite(lb + value)) {
202                 if (isNewIndex(currentIndex)) {
203                     newValues.add(lb + value);
204                 }
205                 value += getStepValue();
206                 currentIndex++;
207             }
208         }
209
210         return newValues;
211     }
212
213     @Override
214     public List<Double> getAllValues() {
215         if (allValues == null) {
216             final double lb = getLowerBound();
217             allValues = new ArrayList<Double>();
218             double currentValue = getStepValue() * getIndex(lb);
219             double value = currentValue - lb;
220
221             if (value == 0 && !containRelative(value)) {
222                 value += getStepValue();
223             }
224
225             while (canAdd(allValues) && containRelative(value) && !Double.isInfinite(lb + value)) {
226                 allValues.add(lb + value);
227                 value += getStepValue();
228             }
229         }
230         return allValues;
231     }
232
233     @Override
234     public LinearGraduations getMore() {
235         if (stepMantissa != 5) {
236             if (moreGraduation == null) {
237                 if (stepMantissa == 1) {
238                     moreGraduation = new LinearGraduations(this, stepExponent - 1, 2);
239                 } else {
240                     moreGraduation = new LinearGraduations(this, stepExponent, 1);
241                 }
242             }
243             return moreGraduation;
244         } else {
245             return null;
246         }
247     }
248
249     @Override
250     public LinearGraduations getAlternative() {
251         if (stepMantissa == 2) {
252             if (alternativeGraduation == null) {
253                 if (getParentGraduations() == null) {
254                     alternativeGraduation =  new LinearGraduations(null, getLowerBound(), true, getLowerBound(), true);
255                 } else {
256                     alternativeGraduation = new LinearGraduations(getParentGraduations(), stepExponent, 5);
257                 }
258             }
259             return alternativeGraduation;
260         } else {
261             return null;
262         }
263     }
264
265     @Override
266     public Graduations getSubGraduations() {
267         if (subGraduation == null) {
268             switch (stepMantissa) {
269                 case 1:
270                     subGraduation = new LinearGraduations(this, stepExponent - 1, 5);
271                     break;
272                 case 2:
273                     subGraduation = new LinearGraduations(this, stepExponent, 1);
274                     break;
275                 case 5:
276                     subGraduation = new LinearGraduations(getParentGraduations(), stepExponent, 1);
277                     break;
278                 default:
279                     subGraduation = null;
280                     break;
281             }
282         }
283         return subGraduation;
284     }
285
286     @Override
287     public int getSubDensity() {
288         if (stepMantissa == 5) {
289             return 5;
290         } else {
291             return 2;
292         }
293     }
294
295     @Override
296     public String toString() {
297         String s = super.toString();
298         s += "; stepMantissa=" + stepMantissa + "; stepExponent=" + stepExponent + "; parent=" + getParentGraduations();
299
300         return s;
301     }
302 }