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 public String toString() {
78 // TODO: Should this use grouping separator ("#,##0.##")?
80 private static final DecimalFormat intFormat = new DecimalFormat("#");
81 private static final DecimalFormat decFormat = new DecimalFormat("0.##");
82 private static final DecimalFormat smallFormat = new DecimalFormat("0.###");
83 private static final DecimalFormat expFormat = new DecimalFormat("0.00E0");
86 * Format the given value (in SI units) to a string representation of the value in this
87 * units. An suitable amount of decimals for the unit are used in the representation.
88 * The unit is not appended to the numerical value.
90 * @param value Value in SI units.
91 * @return A string representation of the number in these units.
93 public String toString(double value) {
94 double val = toUnit(value);
96 if (Math.abs(val) > 1E6) {
97 return expFormat.format(val);
99 if (Math.abs(val) >= 100) {
100 return intFormat.format(val);
102 if (Math.abs(val) <= 0.0005) {
105 if ( Math.abs(val) < 0.095) {
106 return smallFormat.format(val);
109 double sign = Math.signum(val);
116 val = Math.rint(val) / mul * sign;
117 return decFormat.format(val);
122 * Return a string with the specified value and unit. The value is converted into
123 * this unit. If <code>value</code> is NaN, returns "N/A" (not applicable).
125 * @param value the value to print in SI units.
126 * @return the value and unit, or "N/A".
128 public String toStringUnit(double value) {
129 if (Double.isNaN(value))
132 String s = toString(value);
142 * Creates a new Value object with the specified value and this unit.
144 * @param value the value to set.
145 * @return a new Value object.
147 public Value toValue(double value) {
148 return new Value(value, this);
154 * Round the value (in the current units) to a precision suitable for rough valuing
155 * (approximately 2 significant numbers).
157 * @param value Value in current units
158 * @return Rounded value.
160 public abstract double round(double value);
163 * Return the next rounded value after the given value.
164 * @param value Value in these units.
165 * @return The next suitable rounded value.
167 public abstract double getNextValue(double value);
170 * Return the previous rounded value before the given value.
171 * @param value Value in these units.
172 * @return The previous suitable rounded value.
174 public abstract double getPreviousValue(double value);
176 //public abstract ArrayList<Tick> getTicks(double start, double end, double scale);
179 * Return ticks in the range start - end (in current units). minor is the minimum
180 * distance between minor, non-notable ticks and major the minimum distance between
181 * major non-notable ticks. The values are in current units, i.e. no conversion is
184 public abstract Tick[] getTicks(double start, double end, double minor, double major);
187 * Compares whether the two units are equal. Equality requires the unit classes,
188 * multiplier values and units to be equal.
191 public boolean equals(Object other) {
194 if (this.getClass() != other.getClass())
196 return ((this.multiplier == ((Unit) other).multiplier) && this.unit.equals(((Unit) other).unit));
200 public int hashCode() {
201 return this.getClass().hashCode() + this.unit.hashCode();