1 package net.sf.openrocket.unit;
3 import java.text.DecimalFormat;
5 import net.sf.openrocket.util.Chars;
7 public abstract class Unit {
9 /** No unit with 2 digit precision */
10 public static final Unit NOUNIT2 = new GeneralUnit(1, "" + Chars.ZWSP, 2);
12 protected final double multiplier; // meters = units * multiplier
13 protected final String unit;
16 * Creates a new Unit with a given multiplier and unit name.
18 * Multiplier e.g. 1 in = 0.0254 meter
20 * @param multiplier The multiplier to use on the value, 1 this unit == multiplier SI units
21 * @param unit The unit's short form.
23 public Unit(double multiplier, String unit) {
25 throw new IllegalArgumentException("Unit has multiplier=0");
26 this.multiplier = multiplier;
31 * Converts from SI units to this unit. The default implementation simply divides by the
34 * @param value Value in SI unit
35 * @return Value in these units
37 public double toUnit(double value) {
38 return value / multiplier;
42 * Convert from this type of units to SI units. The default implementation simply
43 * multiplies by the multiplier.
45 * @param value Value in these units
46 * @return Value in SI units
48 public double fromUnit(double value) {
49 return value * multiplier;
54 * Return the unit name.
58 public String getUnit() {
63 * Whether the value and unit should be separated by a whitespace. This method
64 * returns true as most units have a space between the value and unit, but may be
67 * @return true if the value and unit should be separated
69 public boolean hasSpace() {
74 // Testcases for toString(double)
75 public static void main(String arg[]) {
76 System.out.println(NOUNIT2.toString(0.0049));
77 System.out.println(NOUNIT2.toString(0.0050));
78 System.out.println(NOUNIT2.toString(0.0051));
79 System.out.println(NOUNIT2.toString(0.00123));
80 System.out.println(NOUNIT2.toString(0.0123));
81 System.out.println(NOUNIT2.toString(0.1234));
82 System.out.println(NOUNIT2.toString(1.2345));
83 System.out.println(NOUNIT2.toString(12.345));
84 System.out.println(NOUNIT2.toString(123.456));
85 System.out.println(NOUNIT2.toString(1234.5678));
86 System.out.println(NOUNIT2.toString(12345.6789));
87 System.out.println(NOUNIT2.toString(123456.789));
88 System.out.println(NOUNIT2.toString(1234567.89));
89 System.out.println(NOUNIT2.toString(12345678.9));
91 System.out.println(NOUNIT2.toString(-0.0049));
92 System.out.println(NOUNIT2.toString(-0.0050));
93 System.out.println(NOUNIT2.toString(-0.0051));
94 System.out.println(NOUNIT2.toString(-0.00123));
95 System.out.println(NOUNIT2.toString(-0.0123));
96 System.out.println(NOUNIT2.toString(-0.1234));
97 System.out.println(NOUNIT2.toString(-1.2345));
98 System.out.println(NOUNIT2.toString(-12.345));
99 System.out.println(NOUNIT2.toString(-123.456));
100 System.out.println(NOUNIT2.toString(-1234.5678));
101 System.out.println(NOUNIT2.toString(-12345.6789));
102 System.out.println(NOUNIT2.toString(-123456.789));
103 System.out.println(NOUNIT2.toString(-1234567.89));
104 System.out.println(NOUNIT2.toString(-12345678.9));
110 public String toString() {
114 // TODO: Should this use grouping separator ("#,##0.##")?
116 private static final DecimalFormat intFormat = new DecimalFormat("#");
117 private static final DecimalFormat decFormat = new DecimalFormat("0.##");
118 private static final DecimalFormat expFormat = new DecimalFormat("0.00E0");
121 * Format the given value (in SI units) to a string representation of the value in this
122 * units. An suitable amount of decimals for the unit are used in the representation.
123 * The unit is not appended to the numerical value.
125 * @param value Value in SI units.
126 * @return A string representation of the number in these units.
128 public String toString(double value) {
129 double val = toUnit(value);
131 if (Math.abs(val) > 1E6) {
132 return expFormat.format(val);
134 if (Math.abs(val) >= 100) {
135 return intFormat.format(val);
137 if (Math.abs(val) <= 0.005) {
141 double sign = Math.signum(val);
148 val = Math.rint(val) / mul * sign;
150 return decFormat.format(val);
155 * Return a string with the specified value and unit. The value is converted into
156 * this unit. If <code>value</code> is NaN, returns "N/A" (not applicable).
158 * @param value the value to print in SI units.
159 * @return the value and unit, or "N/A".
161 public String toStringUnit(double value) {
162 if (Double.isNaN(value))
165 String s = toString(value);
175 * Creates a new Value object with the specified value and this unit.
177 * @param value the value to set.
178 * @return a new Value object.
180 public Value toValue(double value) {
181 return new Value(value, this);
187 * Round the value (in the current units) to a precision suitable for rough valuing
188 * (approximately 2 significant numbers).
190 * @param value Value in current units
191 * @return Rounded value.
193 public abstract double round(double value);
196 * Return the next rounded value after the given value.
197 * @param value Value in these units.
198 * @return The next suitable rounded value.
200 public abstract double getNextValue(double value);
203 * Return the previous rounded value before the given value.
204 * @param value Value in these units.
205 * @return The previous suitable rounded value.
207 public abstract double getPreviousValue(double value);
209 //public abstract ArrayList<Tick> getTicks(double start, double end, double scale);
212 * Return ticks in the range start - end (in current units). minor is the minimum
213 * distance between minor, non-notable ticks and major the minimum distance between
214 * major non-notable ticks. The values are in current units, i.e. no conversion is
217 public abstract Tick[] getTicks(double start, double end, double minor, double major);
220 * Compares whether the two units are equal. Equality requires the unit classes,
221 * multiplier values and units to be equal.
224 public boolean equals(Object other) {
227 if (this.getClass() != other.getClass())
229 return ((this.multiplier == ((Unit) other).multiplier) && this.unit.equals(((Unit) other).unit));
233 public int hashCode() {
234 return this.getClass().hashCode() + this.unit.hashCode();