1 package net.sf.openrocket.unit;
3 import java.text.DecimalFormat;
4 import java.text.NumberFormat;
5 import java.util.ArrayList;
7 public class FractionalUnit extends Unit {
9 private final static String fraction = "\u2044";
11 private final static String[] numerator = {
24 private final static String[] denominator = {
37 // This is the base of the fractions. ie, 16d for 1/16ths.
38 private final int fractionBase;
39 // This is 1d/fractionBase;
40 private final double fractionValue;
42 // This is the value used when incrementing/decrementing.
43 private final double incrementValue;
45 // If the actual value differs from the decimal representation by more than this,
46 // we display as decimals.
47 private final double epsilon;
49 private final String unitLabel;
51 public FractionalUnit(double multiplier, String unit, String unitLabel, int fractionBase, double incrementValue) {
52 this( multiplier, unit, unitLabel, fractionBase, incrementValue, 0.1d/fractionBase);
55 public FractionalUnit(double multiplier, String unit, String unitLabel, int fractionBase, double incrementValue, double epsilon) {
56 super(multiplier, unit);
57 this.unitLabel = unitLabel;
58 this.fractionBase = fractionBase;
59 this.fractionValue = 1.0d/fractionBase;
60 this.incrementValue = incrementValue;
61 this.epsilon = epsilon;
65 public double round(double value) {
66 return roundTo( value, fractionValue );
69 private double roundTo( double value, double fraction ) {
70 double remainder = Math.IEEEremainder( value, fraction );
71 return value - remainder;
75 public double getNextValue(double value) {
76 double rounded = roundTo(value, incrementValue);
77 if ( rounded <= value + epsilon) {
78 rounded += incrementValue;
84 public double getPreviousValue(double value) {
85 double rounded = roundTo(value, incrementValue);
86 if ( rounded >= value - epsilon ) {
87 rounded -= incrementValue;
93 public Tick[] getTicks(double start, double end, double minor, double major) {
95 start = toUnit(start);
97 minor = toUnit(minor);
98 major = toUnit(major);
100 if (minor <= 0 || major <= 0 || major < minor) {
101 throw new IllegalArgumentException("getTicks called with minor="+minor+" major="+major);
104 ArrayList<Tick> ticks = new ArrayList<Tick>();
106 int mod2,mod3,mod4; // Moduli for minor-notable, major-nonnotable, major-notable
109 // Find the smallest possible step size
118 // Find step size for major ticks
124 if (one/2 >= major) {
125 // major step is round-five, major-notable is next round-ten
126 double majorstep = one/2;
127 mod3 = (int)Math.round(majorstep/minstep);
130 // major step is round-ten, major-notable is next round-ten
131 mod3 = (int)Math.round(one/minstep);
134 // Check for clashes between minor-notable and major-nonnotable
137 mod2 = 1; // Every minor tick is notable
139 mod2 = 5; // Every fifth minor tick is notable
143 // Calculate starting position
144 int pos = (int)Math.ceil(start/minstep);
145 // System.out.println("mod2="+mod2+" mod3="+mod3+" mod4="+mod4);
146 while (pos*minstep <= end) {
147 double unitValue = pos*minstep;
148 double value = fromUnit(unitValue);
151 ticks.add(new Tick(value,unitValue,true,true));
152 else if (pos%mod3 == 0)
153 ticks.add(new Tick(value,unitValue,true,false));
154 else if (pos%mod2 == 0)
155 ticks.add(new Tick(value,unitValue,false,true));
157 ticks.add(new Tick(value,unitValue,false,false));
162 return ticks.toArray(new Tick[0]);
167 public String toString(double value) {
169 double correctVal = toUnit(value);
170 double val = round(correctVal);
173 if ( Math.abs( val - correctVal ) > epsilon ) {
174 NumberFormat decFormat = new DecimalFormat("#.###");
175 return decFormat.format(correctVal);
178 NumberFormat intFormat = new DecimalFormat("#");
179 double sign = Math.signum(val);
181 double posValue = sign * val;
183 double intPart = Math.floor(posValue);
185 double frac = Math.rint((posValue - intPart)/fractionValue);
186 double fracBase = fractionBase;
189 while ( frac > 0 && fracBase > 2 && frac % 2 == 0 ) {
197 return intFormat.format(posValue);
198 } else if (intPart == 0.0 ){
199 return (sign <0 ? "-" : "" ) + numeratorString(Double.valueOf(frac).intValue())
200 + fraction + denominatorString(Double.valueOf(fracBase).intValue());
202 return intFormat.format(sign*intPart) + " " + numeratorString(Double.valueOf(frac).intValue())
203 + fraction + denominatorString(Double.valueOf(fracBase).intValue());
208 private String numeratorString( int value ) {
214 while ( value > 0 ) {
215 rep = numerator[ value % 10 ] + rep;
221 private String denominatorString( int value ) {
226 while ( value > 0 ) {
227 rep = denominator[ value % 10 ] + rep;
234 public String toStringUnit(double value) {
235 if (Double.isNaN(value))
238 String s = toString(value);
239 s += " " + unitLabel;