scirenderer: bound iteration Graduation
[scilab.git] / scilab / modules / scirenderer / src / org / scilab / forge / scirenderer / ruler / graduations / LogarithmicGraduations.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-2015 - 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.Collections;
19 import java.util.ArrayList;
20 import java.util.List;
21
22 /**
23  * @author Pierre Lando
24  */
25 public final class LogarithmicGraduations extends AbstractGraduations implements Graduations {
26
27     /**
28      * Exponent of the step.
29      * Possible value are : 1, 2 and 3*k with k > 0
30      */
31     private final int stepExponent;
32
33     private List<Double> allValues;
34     private Graduations subGraduation;
35     private Graduations moreGraduation;
36     private Graduations alternativeGraduation;
37
38     /**
39      * Private child constructor.
40      * The interval is copied from parent's one.
41      * @param parentGraduations the parent graduation.
42      * @param stepExponent the step exponent.
43      */
44     private LogarithmicGraduations(Graduations parentGraduations, int stepExponent) {
45         super(parentGraduations);
46         this.stepExponent = stepExponent;
47     }
48
49     /**
50      * Private root graduation constructor.
51      * This graduation has no parent.
52      * @param lowerBound actual lower bound.
53      * @param lowerBoundIncluded true if the lower bound is included in the interval.
54      * @param upperBound actual upper bound.
55      * @param upperBoundIncluded true if the upper bound is included in the interval.
56      */
57     private LogarithmicGraduations(double lowerBound, boolean lowerBoundIncluded, double upperBound, boolean upperBoundIncluded) {
58         super(lowerBound, lowerBoundIncluded, upperBound, upperBoundIncluded);
59         if (lowerBound != upperBound) {
60             stepExponent = 1;
61         } else {
62             stepExponent = 0;
63             allValues = new ArrayList<Double>();
64             allValues.add(lowerBound);
65         }
66     }
67
68     public static LogarithmicGraduations create(double lowerBound, double upperBound) {
69         return create(lowerBound, true, upperBound, true);
70     }
71
72     public static LogarithmicGraduations create(double lowerBound, boolean lowerBoundIncluded, double upperBound, boolean upperBoundIncluded) {
73         if (lowerBound < upperBound) {
74             return new LogarithmicGraduations(lowerBound, lowerBoundIncluded, upperBound, upperBoundIncluded);
75         } else {
76             return new LogarithmicGraduations(upperBound, upperBoundIncluded, lowerBound, lowerBoundIncluded);
77         }
78     }
79
80     @Override
81     public List<Double> getAllValues() {
82         if (allValues == null) {
83             allValues = new ArrayList<Double>();
84             int currentExponent = (int) Math.ceil(Math.log10(getLowerBound()));
85             double currentValue = Math.pow(10, currentExponent);
86             final double step = Math.pow(10, stepExponent);
87
88             if ((currentValue == getLowerBound()) && (!isLowerBoundIncluded())) {
89                 currentValue *= step;
90             }
91
92             while (contain(currentValue) && !Double.isInfinite(currentValue)) {
93                 allValues.add(currentValue);
94                 currentValue *= step;
95             }
96         }
97         return allValues;
98     }
99
100     @Override
101     public List<Double> getNewValues() {
102         return getAllValues();
103     }
104
105     @Override
106     public Graduations getMore() {
107         if (moreGraduation == null) {
108             moreGraduation = new LinLogGraduation(this);
109         }
110         return moreGraduation;
111     }
112
113     @Override
114     public Graduations getAlternative() {
115         if (alternativeGraduation == null) {
116             int nextStep = 3 + stepExponent - stepExponent % 3;
117             alternativeGraduation = new LogarithmicGraduations(this, nextStep);
118         }
119         return alternativeGraduation;
120     }
121
122     @Override
123     public Graduations getSubGraduations() {
124         if (subGraduation == null) {
125             if (stepExponent > 1) {
126                 subGraduation = new LogarithmicGraduations(this, stepExponent / 3);
127             } else {
128                 subGraduation = new LinLogGraduation(this).getSubGraduations();
129             }
130         }
131         return subGraduation;
132     }
133
134     @Override
135     public List<Double> getSubGraduations(final int N) {
136         if (subValues == null) {
137             List<Double> ticksValue = getAllValues();
138             if (N == 0 || ticksValue.size() == 0) {
139                 subValues = new ArrayList<Double>();
140             } else {
141                 Collections.sort(ticksValue);
142                 subValues = new ArrayList<Double>();
143
144                 for (int i = 0; i < ticksValue.size() - 1; i++) {
145                     final double first = Math.log10(ticksValue.get(i));
146                     final double second = Math.log10(ticksValue.get(i + 1));
147                     final double step = (second - first) / (N + 1);
148                     double v = first;
149                     for (int j = 0; j <= N; j++) {
150                         subValues.add(Math.pow(10, v));
151                         v += step;
152                     }
153                 }
154                 subValues.add(ticksValue.get(ticksValue.size() - 1));
155             }
156         }
157
158         return subValues;
159     }
160
161     @Override
162     public int getSubDensity() {
163         if (stepExponent >= 3) {
164             return 3;
165         } else if (stepExponent == 2) {
166             return stepExponent;
167         } else {
168             return getSubGraduations().getSubDensity();
169         }
170     }
171
172     @Override
173     public String toString() {
174         String s = super.toString();
175         s += "; stepExponent=" + stepExponent + "; parent=" + getParentGraduations();
176
177         return s;
178     }
179
180     /**
181      * This class manage linear graduation between 10^n and 10^(n+1)
182      */
183     private class LinLogGraduation extends AbstractGraduations implements Graduations {
184         private Graduations alternativeLLGraduation;
185         private Graduations moreLLGraduation;
186         private Graduations subLLGraduation;
187
188         private List<Double> allValues;
189         private List<Double> newValues;
190
191         private final List<Graduations> graduationsList;
192
193         public LinLogGraduation(LogarithmicGraduations parentGraduations) {
194             super(parentGraduations);
195             graduationsList = computeGraduationsList();
196         }
197
198         private LinLogGraduation(Graduations parentGraduations, List<Graduations> graduationsList) {
199             super(parentGraduations);
200             this.graduationsList = graduationsList;
201         }
202
203         @Override
204         public List<Double> getAllValues() {
205             if (allValues == null) {
206                 allValues = new ArrayList<Double>();
207                 for (Graduations graduations : graduationsList) {
208                     allValues.addAll(graduations.getAllValues());
209                 }
210
211                 allValues.addAll(getLogarithmicParent().getAllValues());
212             }
213             return allValues;
214         }
215
216         @Override
217         public List<Double> getNewValues() {
218             if (newValues == null) {
219                 newValues = new ArrayList<Double>();
220                 if (getParentGraduations() instanceof LogarithmicGraduations) {
221                     for (Graduations graduations : graduationsList) {
222                         newValues.addAll(graduations.getAllValues());
223                     }
224                 } else {
225                     for (Graduations graduations : graduationsList) {
226                         newValues.addAll(graduations.getNewValues());
227                     }
228                 }
229             }
230             return newValues;
231         }
232
233         @Override
234         public Graduations getMore() {
235             if (moreLLGraduation == null) {
236                 List<Graduations> moreList = new ArrayList<Graduations>();
237                 for (Graduations graduations : graduationsList) {
238                     Graduations more = graduations.getMore();
239                     if (more != null) {
240                         moreList.add(more);
241                     }
242                 }
243                 if (!moreList.isEmpty()) {
244                     moreLLGraduation = new LinLogGraduation(this, moreList);
245                 }
246             }
247             return moreLLGraduation;
248         }
249
250         @Override
251         public Graduations getAlternative() {
252             if (alternativeLLGraduation == null) {
253                 List<Graduations> alternativeList = new ArrayList<Graduations>();
254                 for (Graduations graduations : graduationsList) {
255                     Graduations alternative = graduations.getAlternative();
256                     if (alternative != null) {
257                         alternativeList.add(alternative);
258                     }
259                 }
260                 if (!alternativeList.isEmpty()) {
261                     alternativeLLGraduation = new LinLogGraduation(this, alternativeList);
262                 }
263             }
264             return alternativeLLGraduation;
265         }
266
267         @Override
268         public Graduations getSubGraduations() {
269             if (subLLGraduation == null) {
270                 List<Graduations> subList = new ArrayList<Graduations>();
271                 for (Graduations graduations : graduationsList) {
272                     Graduations sub = graduations.getSubGraduations();
273                     if (sub != null) {
274                         subList.add(sub);
275                     }
276                 }
277                 if (subList.isEmpty()) {
278                     subLLGraduation = getMore().getSubGraduations();
279                 } else {
280                     subLLGraduation = new LinLogGraduation(this, subList);
281                 }
282             }
283             return subLLGraduation;
284         }
285
286         @Override
287         public int getSubDensity() {
288             return 0;
289         }
290
291         private List<Graduations> computeGraduationsList() {
292             List<Graduations> list = new ArrayList<Graduations>();
293
294             /**
295              * Let a and b a power of 10.
296              * lowerBound < a < b < upperBound
297              */
298
299             double aPower = Math.ceil(Math.log10(getLowerBound()));
300             double bPower = Math.floor(Math.log10(getUpperBound()));
301             double a = Math.pow(10, aPower);
302             double b = Math.pow(10, bPower);
303
304             if (aPower > bPower) {
305                 // Case of 10^n <= a < b <= 10^(n+1)
306                 list.add(LinearGraduations.create(
307                              this,
308                              getLowerBound(), true,
309                              getUpperBound(), true
310                          ));
311             } else {
312                 if (a != getLowerBound()) {
313                     list.add(LinearGraduations.create(
314                                  this,
315                                  getLowerBound(), true,
316                                  a, false
317                              ));
318                 }
319
320                 if (aPower != bPower) {
321                     // Limit iterations on power smaller than 10^310 (Max double ~ 10^308)
322                     for (double i = aPower; i < Math.min(bPower, 310); i++) {
323                         list.add(LinearGraduations.create(
324                                      this,
325                                      Math.pow(10, i), false,
326                                      Math.pow(10, i + 1), false
327                                  ));
328                     }
329                 }
330
331                 if (b != getUpperBound()) {
332                     list.add(LinearGraduations.create(
333                                  this,
334                                  b, false,
335                                  getUpperBound(), true
336                              ));
337                 }
338             }
339
340             return list;
341         }
342
343         private Graduations getLogarithmicParent() {
344             Graduations currentGraduation = getParentGraduations();
345             while (!(currentGraduation instanceof LogarithmicGraduations)) {
346                 currentGraduation = currentGraduation.getParentGraduations();
347             }
348             return currentGraduation;
349         }
350     }
351 }