c7dbddb00628ad3d4ae1970470da233f66e06355
[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.LinkedList;
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 LinkedList<Double>();
74             allValues = new LinkedList<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     @Override
178     public List<Double> getNewValues() {
179         if (getParentGraduations() == null) {
180             return getAllValues();
181         }
182
183         if (newValues == null) {
184             newValues = new LinkedList<Double>();
185             final double lb = getLowerBound();
186
187             long currentIndex = getIndex(lb);
188             double currentValue = getStepValue() * currentIndex;
189             double value = currentValue - lb;
190
191             if (value == 0 && !containRelative(value)) {
192                 value += getStepValue();
193                 currentIndex++;
194             }
195
196             while (containRelative(value) && !Double.isInfinite(lb + value)) {
197                 if (isNewIndex(currentIndex)) {
198                     newValues.add(lb + value);
199                 }
200                 value += getStepValue();
201                 currentIndex++;
202             }
203         }
204
205         return newValues;
206     }
207
208     @Override
209     public List<Double> getAllValues() {
210         if (allValues == null) {
211             final double lb = getLowerBound();
212             allValues = new LinkedList<Double>();
213             double currentValue = getStepValue() * getIndex(lb);
214             double value = currentValue - lb;
215
216             if (value == 0 && !containRelative(value)) {
217                 value += getStepValue();
218             }
219
220             while (containRelative(value) && !Double.isInfinite(lb + value)) {
221                 allValues.add(lb + value);
222                 value += getStepValue();
223             }
224         }
225         return allValues;
226     }
227
228     @Override
229     public LinearGraduations getMore() {
230         if (stepMantissa != 5) {
231             if (moreGraduation == null) {
232                 if (stepMantissa == 1) {
233                     moreGraduation = new LinearGraduations(this, stepExponent - 1, 2);
234                 } else {
235                     moreGraduation = new LinearGraduations(this, stepExponent, 1);
236                 }
237             }
238             return moreGraduation;
239         } else {
240             return null;
241         }
242     }
243
244     @Override
245     public LinearGraduations getAlternative() {
246         if (stepMantissa == 2) {
247             if (alternativeGraduation == null) {
248                 if (getParentGraduations() == null) {
249                     alternativeGraduation =  new LinearGraduations(null, getLowerBound(), true, getLowerBound(), true);
250                 } else {
251                     alternativeGraduation = new LinearGraduations(getParentGraduations(), stepExponent, 5);
252                 }
253             }
254             return alternativeGraduation;
255         } else {
256             return null;
257         }
258     }
259
260     @Override
261     public Graduations getSubGraduations() {
262         if (subGraduation == null) {
263             switch (stepMantissa) {
264                 case 1:
265                     subGraduation = new LinearGraduations(this, stepExponent - 1, 5);
266                     break;
267                 case 2:
268                     subGraduation = new LinearGraduations(this, stepExponent, 1);
269                     break;
270                 case 5:
271                     subGraduation = new LinearGraduations(getParentGraduations(), stepExponent, 1);
272                     break;
273                 default:
274                     subGraduation = null;
275                     break;
276             }
277         }
278         return subGraduation;
279     }
280
281     @Override
282     public int getSubDensity() {
283         if (stepMantissa == 5) {
284             return 5;
285         } else {
286             return 2;
287         }
288     }
289
290     @Override
291     public String toString() {
292         String s = super.toString();
293         s += "; stepMantissa=" + stepMantissa + "; stepExponent=" + stepExponent + "; parent=" + getParentGraduations();
294
295         return s;
296     }
297 }