create changelog entry
[debian/openrocket] / core / src / net / sf / openrocket / unit / GeneralUnit.java
1 package net.sf.openrocket.unit;
2
3 import java.util.ArrayList;
4
5 public class GeneralUnit extends Unit {
6
7         private final int significantNumbers;
8         private final int decimalRounding;
9         
10         // Values smaller that this are rounded using decimal rounding
11         // [pre-calculated as 10^(significantNumbers-1)]
12         private final double decimalLimit; 
13         
14         // Pre-calculated as 10^significantNumbers
15         private final double significantNumbersLimit;
16         
17         
18         public GeneralUnit(double multiplier, String unit) {
19                 this(multiplier, unit, 2, 10);
20         }
21         
22         public GeneralUnit(double multiplier, String unit, int significantNumbers) {
23                 this(multiplier, unit, significantNumbers, 10);
24         }
25         
26         public GeneralUnit(double multiplier, String unit, int significantNumbers, int decimalRounding) {
27                 super(multiplier, unit);
28                 assert(significantNumbers>0);
29                 assert(decimalRounding>0);
30                 
31                 this.significantNumbers = significantNumbers;
32                 this.decimalRounding = decimalRounding;
33                 
34                 double d=1;
35                 double e=10;
36                 for (int i=1; i<significantNumbers; i++) {
37                         d *= 10.0;
38                         e *= 10.0;
39                 }
40                 decimalLimit = d;
41                 significantNumbersLimit = e;
42         }
43
44         @Override
45         public double round(double value) {
46                 if (value < decimalLimit) {
47                         // Round to closest 1/decimalRounding
48                         return Math.rint(value*decimalRounding)/decimalRounding;
49                 } else {
50                         // Round to given amount of significant numbers
51                         double m = 1;
52                         while (value >= significantNumbersLimit) {
53                                 m *= 10.0;
54                                 value /= 10.0;
55                         }
56                         return Math.rint(value)*m;
57                 }
58         }
59
60         
61         
62
63         // TODO: LOW: untested
64         // start, end and scale in this units
65 //      @Override
66         public ArrayList<Tick> getTicks(double start, double end, double scale) {
67                 ArrayList<Tick> ticks = new ArrayList<Tick>();
68                 double delta;
69                 int normal, major;
70
71                 // TODO: LOW: more fine-grained (e.g.  0||||5||||10||||15||||20)
72                 if (scale <= 1.0/decimalRounding) {
73                         delta = 1.0/decimalRounding;
74                         normal = 1;
75                         major = decimalRounding;
76                 } else if (scale <= 1.0) {
77                         delta = 1.0/decimalRounding;
78                         normal = decimalRounding;
79                         major = decimalRounding*10;
80                 } else {
81                         double r = scale;
82                         delta = 1;
83                         while (r > 10) {
84                                 r /= 10;
85                                 delta *= 10;
86                         }
87                         normal = 10;
88                         major = 100;   // TODO: LOW: More fine-grained with 5
89                 }
90                 
91                 double v = Math.ceil(start/delta)*delta;
92                 int n = (int)Math.round(v/delta);
93                 
94 //              while (v <= end) {
95 //                      if (n%major == 0)
96 //                              ticks.add(new Tick(v,Tick.MAJOR));
97 //                      else if (n%normal == 0)
98 //                              ticks.add(new Tick(v,Tick.NORMAL));
99 //                      else
100 //                              ticks.add(new Tick(v,Tick.MINOR));
101 //                      v += delta;
102 //                      n++;
103 //              }
104                 
105                 return ticks;
106         }
107         
108         @Override
109         public Tick[] getTicks(double start, double end, double minor, double major) {
110                 // Convert values
111                 start = toUnit(start);
112                 end = toUnit(end);
113                 minor = toUnit(minor);
114                 major = toUnit(major);
115                 
116                 if (minor <= 0 || major <= 0 || major < minor) {
117                         throw new IllegalArgumentException("getTicks called with minor="+minor+" major="+major);
118                 }
119                 
120                 ArrayList<Tick> ticks = new ArrayList<Tick>();
121                 
122                 int mod2,mod3,mod4;  // Moduli for minor-notable, major-nonnotable, major-notable
123                 double minstep;
124
125                 // Find the smallest possible step size
126                 double one=1;
127                 while (one > minor)
128                         one /= 10;
129                 while (one < minor)
130                         one *= 10;
131                 // one is the smallest round-ten that is larger than minor
132                 if (one/2 >= minor) {
133                         // smallest step is round-five
134                         minstep = one/2;
135                         mod2 = 2;  // Changed later if clashes with major ticks
136                 } else {
137                         minstep = one;
138                         mod2 = 10;  // Changed later if clashes with major ticks
139                 }
140                 
141                 // Find step size for major ticks
142                 one = 1;
143                 while (one > major)
144                         one /= 10;
145                 while (one < major)
146                         one *= 10;
147                 if (one/2 >= major) {
148                         // major step is round-five, major-notable is next round-ten
149                         double majorstep = one/2;
150                         mod3 = (int)Math.round(majorstep/minstep);
151                         mod4 = mod3*2;
152                 } else {
153                         // major step is round-ten, major-notable is next round-ten
154                         mod3 = (int)Math.round(one/minstep);
155                         mod4 = mod3*10;
156                 }
157                 // Check for clashes between minor-notable and major-nonnotable
158                 if (mod3 == mod2) {
159                         if (mod2==2)
160                                 mod2 = 1;  // Every minor tick is notable
161                         else
162                                 mod2 = 5;  // Every fifth minor tick is notable
163                 }
164
165
166                 // Calculate starting position
167                 int pos = (int)Math.ceil(start/minstep);
168 //              System.out.println("mod2="+mod2+" mod3="+mod3+" mod4="+mod4);
169                 while (pos*minstep <= end) {
170                         double unitValue = pos*minstep;
171                         double value = fromUnit(unitValue);
172                         
173                         if (pos%mod4 == 0)
174                                 ticks.add(new Tick(value,unitValue,true,true));
175                         else if (pos%mod3 == 0)
176                                 ticks.add(new Tick(value,unitValue,true,false));
177                         else if (pos%mod2 == 0)
178                                 ticks.add(new Tick(value,unitValue,false,true));
179                         else
180                                 ticks.add(new Tick(value,unitValue,false,false));
181                         
182                         pos++;
183                 }
184                 
185                 return ticks.toArray(new Tick[0]);
186         }
187         
188         
189         @Override
190         public double getNextValue(double value) {
191                 // TODO: HIGH: Auto-generated method stub
192                 return value+1;
193         }
194
195         @Override
196         public double getPreviousValue(double value) {
197                 // TODO: HIGH: Auto-generated method stub
198                 return value-1;
199         }
200         
201         
202         ///// TESTING:
203         
204         private static void printTicks(double start, double end, double minor, double major) {
205                 Tick[] ticks = Unit.NOUNIT2.getTicks(start, end, minor, major);
206                 String str = "Ticks for ("+start+","+end+","+minor+","+major+"):";
207                 for (int i=0; i<ticks.length; i++) {
208                         str += " "+ticks[i].value;
209                         if (ticks[i].major) {
210                                 if (ticks[i].notable)
211                                         str += "*";
212                                 else
213                                         str += "o";
214                         } else {
215                                 if (ticks[i].notable)
216                                         str += "_";
217                                 else
218                                         str += " ";
219                         }
220                 }
221                 System.out.println(str);
222         }
223         public static void main(String[] arg) {
224                 printTicks(0,100,1,10);
225                 printTicks(4.7,11.0,0.15,0.7);
226         }
227         
228 }