package com.billkuker.rocketry.motorsim;\r
\r
+import java.lang.ref.WeakReference;\r
+import java.lang.reflect.Field;\r
+import java.lang.reflect.Modifier;\r
import java.text.DecimalFormat;\r
import java.text.NumberFormat;\r
import java.util.HashSet;\r
+import java.util.Iterator;\r
import java.util.Set;\r
import java.util.prefs.Preferences;\r
\r
import javax.measure.unit.Unit;\r
import javax.measure.unit.UnitFormat;\r
\r
+import org.apache.log4j.Logger;\r
import org.jscience.physics.amount.Amount;\r
\r
public class RocketScience {\r
+ private static final Logger log = Logger.getLogger(RocketScience.class);\r
+ \r
public static Unit<Pressure> PSI = new ProductUnit<Pressure>(NonSI.POUND_FORCE.divide(NonSI.INCH.pow(2)));\r
public static Unit<Impulse> NEWTON_SECOND = new ProductUnit<Impulse>(SI.NEWTON.times(SI.SECOND));\r
+ public static Unit<Impulse> POUND_SECOND = new ProductUnit<Impulse>(NonSI.POUND_FORCE.times(SI.SECOND));\r
static{\r
UnitFormat.getInstance().label(PSI, "psi");\r
UnitFormat.getInstance().label(NEWTON_SECOND, "Ns");\r
public interface Impulse extends Quantity {\r
public static Unit<Impulse> UNIT = NEWTON_SECOND;\r
}\r
+ \r
+ private static HashSet<WeakReference<UnitPreferenceListener>> prefListeners = new HashSet<WeakReference<UnitPreferenceListener>>();\r
+ public static interface UnitPreferenceListener{\r
+ public void preferredUnitsChanged();\r
+ }\r
+ public static void addUnitPreferenceListener(UnitPreferenceListener l){\r
+ prefListeners.add(new WeakReference<RocketScience.UnitPreferenceListener>(l));\r
+ }\r
\r
public static enum UnitPreference{\r
SI(new Unit[]{\r
+ javax.measure.unit.SI.METERS_PER_SECOND,\r
+ javax.measure.unit.SI.MILLIMETER.pow(3),\r
javax.measure.unit.SI.MILLIMETER.pow(2),\r
javax.measure.unit.SI.MILLIMETER,\r
javax.measure.unit.SI.MILLIMETER.divide(javax.measure.unit.SI.SECOND),\r
javax.measure.unit.SI.NEWTON,\r
+ javax.measure.unit.SI.GRAM,\r
javax.measure.unit.SI.MEGA(javax.measure.unit.SI.PASCAL),\r
NEWTON_SECOND\r
}),\r
NONSI(new Unit[]{\r
+ javax.measure.unit.NonSI.MILES_PER_HOUR,\r
+ javax.measure.unit.NonSI.INCH.pow(3),\r
javax.measure.unit.NonSI.INCH.pow(2),\r
javax.measure.unit.NonSI.INCH,\r
javax.measure.unit.NonSI.POUND_FORCE,\r
+ javax.measure.unit.NonSI.OUNCE,\r
javax.measure.unit.NonSI.INCH.divide(javax.measure.unit.SI.SECOND),\r
PSI,\r
- NEWTON_SECOND\r
+ POUND_SECOND\r
});\r
\r
private static UnitPreference preference = SI;\r
}\r
\r
public static void setUnitPreference( final UnitPreference up ){\r
+ if ( preference == up )\r
+ return;\r
preference = up;\r
Preferences prefs = Preferences.userNodeForPackage(RocketScience.class);\r
prefs.put("PreferedUnits", up.toString());\r
+ Iterator<WeakReference<UnitPreferenceListener>> weakIter = prefListeners.iterator();\r
+ while (weakIter.hasNext()) {\r
+ WeakReference<UnitPreferenceListener> weak = weakIter.next();\r
+ UnitPreferenceListener l = weak.get();\r
+ if (l != null) {\r
+ l.preferredUnitsChanged();\r
+ } else {\r
+ log.debug("Weak reference to UPE is null");\r
+ weakIter.remove();\r
+ }\r
+ }\r
}\r
\r
protected Set<Unit<?>> units = new HashSet<Unit<?>>();\r
}\r
return u;\r
}\r
+ \r
+ @SuppressWarnings("unchecked")\r
+ public <T extends Quantity> Unit<T> getPreferredUnit(Class<T> q){\r
+ for( Unit<?> u : units ){\r
+ try {\r
+ return u.asType(q); \r
+ } catch ( ClassCastException e ) {\r
+ //Not compatible\r
+ }\r
+ }\r
+ try {\r
+ Field f = q.getDeclaredField("UNIT");\r
+ if ( Modifier.isStatic(f.getModifiers()) ){\r
+ if ( Unit.class.isAssignableFrom(f.getType())){\r
+ return (Unit<T>)f.get(null);\r
+ }\r
+ }\r
+ } catch (SecurityException e) {\r
+ e.printStackTrace();\r
+ } catch (NoSuchFieldException e) {\r
+ e.printStackTrace();\r
+ } catch (IllegalArgumentException e) {\r
+ log.error(e);\r
+ } catch (IllegalAccessException e) {\r
+ log.error(e);\r
+ }\r
+ return null;\r
+ }\r
}\r
\r
public static <T extends Quantity> String ammountToString(Amount<T> a) {\r
+ if ( a == null )\r
+ return "Null";\r
final NumberFormat nf = new DecimalFormat("##########.###");\r
return nf.format(a.doubleValue(a.getUnit())) + " " + a.getUnit();\r
}\r
\r
+ @SuppressWarnings("unchecked")\r
public static <T extends Quantity> String ammountToRoundedString(Amount<T> a) {\r
if (a == null)\r
- return "NULL";\r
+ return "Null";\r
Unit<T> u = RocketScience.UnitPreference.preference.getPreferredUnit(a\r
.getUnit());\r
double d = a.doubleValue(u);\r
\r
DecimalFormat df;\r
+ \r
+ if (u == SI.MILLIMETER && d > 1000.0) {\r
+ u = (Unit<T>) SI.METER;\r
+ d = d / 1000.0;\r
+ } else if (u == NonSI.INCH && d > 12.0) {\r
+ u = (Unit<T>) NonSI.FOOT;\r
+ d = d / 12.0;\r
+ }\r
\r
if (Math.abs(d) < 10.0) {\r
df = new DecimalFormat("#.##");\r