diff --git a/app/build.gradle b/app/build.gradle index 0755b9a8..2bf0e75b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -74,7 +74,7 @@ dependencies { implementation "com.android.support:support-v4:${versions.supportLib}" implementation "com.android.support:appcompat-v7:${versions.supportLib}" implementation "com.android.support:design:${versions.supportLib}" - implementation "javax.measure:jsr-275:0.9.1" + implementation project(":measure") implementation 'com.squareup:otto:1.3.9-SNAPSHOT' annotationProcessor 'com.squareup:otto:1.3.9-SNAPSHOT' annotationProcessor 'com.squareup:otto-compiler:1.3.9-SNAPSHOT' diff --git a/measure/.gitignore b/measure/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/measure/.gitignore @@ -0,0 +1 @@ +/build diff --git a/measure/build.gradle b/measure/build.gradle new file mode 100644 index 00000000..c367e675 --- /dev/null +++ b/measure/build.gradle @@ -0,0 +1,9 @@ +apply plugin: 'java-library' + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + +} + +sourceCompatibility = "7" +targetCompatibility = "7" diff --git a/measure/src/main/java/javax/measure/DecimalMeasure.java b/measure/src/main/java/javax/measure/DecimalMeasure.java new file mode 100644 index 00000000..05f337a9 --- /dev/null +++ b/measure/src/main/java/javax/measure/DecimalMeasure.java @@ -0,0 +1,178 @@ +/* + * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences. + * Copyright (C) 2007 - JScience (http://jscience.org/) + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software is + * freely granted, provided that this notice is preserved. + */ +package javax.measure; + +import java.math.BigDecimal; +import java.math.MathContext; + +import javax.measure.converter.AddConverter; +import javax.measure.converter.RationalConverter; +import javax.measure.converter.UnitConverter; +import javax.measure.quantity.Quantity; +import javax.measure.unit.Unit; + +/** + *
This class represents a measure whose value is an arbitrary-precision + * decimal number.
+ * + * When converting, applications may supply the
+ * This interface represents the measurable, countable, or comparable
+ * property or aspect of a thing. Implementing instances are typically the result of a measurement:[code]
+ * Measurable Although measurable instances are for the most part scalar quantities;
+ * more complex implementations (e.g. vectors, data set) are allowed as
+ * long as an aggregate magnitude can be determined. For example:[code]
+ * class Velocity3D implements Measurable Note: This method differs from the This class represents the result of a measurement stated in a
+ * known unit. There is no constraint upon the measurement value itself: scalars,
+ * vectors, or even data sets are valid values as long as
+ * an aggregate magnitude can be determined (see {@link Measurable}). Note: This method differs from the Note: This method differs from the This class provides the interface for formatting and parsing {@link
+ * Measure measures}. As a minimum, instances of this class should be able to parse/format
+ * measure using {@link CompoundUnit}. This class represents a measurement vector of two or more dimensions.
+ * For example:[code]
+ * VectorMeasure Subclasses may provide fixed dimensions specializations:[code]
+ * class Velocity2D extends VectorMeasure Measurement vectors may use {@link CompoundUnit compound units}:[code]
+ * VectorMeasure Instances of this class (and sub-classes) are immutable. This class represents a converter adding a constant offset
+ * (approximated as a Instances of this class are immutable. This class represents a logarithmic converter. Such converter
+ * is typically used to create logarithmic unit. For example:[code]
+ * Unit Instances of this class are immutable. This class represents a converter multiplying numeric values by a
+ * constant scaling factor (approximated as a Instances of this class are immutable. This class represents a converter multiplying numeric values by an
+ * exact scaling factor (represented as the quotient of two
+ * Instances of this class are immutable. This class represents a converter of numeric values. It is not required for sub-classes to be immutable
+ * (e.g. currency converter). Sub-classes must ensure unicity of the {@link #IDENTITY identity}
+ * converter. In other words, if the result of an operation is equivalent
+ * to the identity converter, then the unique {@link #IDENTITY} instance
+ * should be returned. Note: Implementations must ensure that the {@link #IDENTITY} instance
+ * is returned if the resulting converter is an identity
+ * converter. Provides support for unit conversion. Provides strongly typed measurements to enforce compile-time
+ check of parameters consistency and avoid interface errors. Let's take the following example:[code]
+ class Person {
+ void setWeight(double weight);
+ }[/code]
+ Should the weight be in pound, kilogram ?? Users may create their own {@link javax.measure.Measurable
+ Measurable} implementation:[code]
+
+ public class Period implements Measurable Users may also combine a definite amount (scalar, vector, collection, etc.)
+ to a unit and make it a {@link javax.measure.Measure Measure} (and
+ a {@link javax.measure.Measurable Measurable} instance). For example:
+ [code]
+
+ // Scalar measurement (numerical).
+ person.setWeight(Measure.valueOf(180.0, POUND)); // Measure This interface represents any type of quantitative properties or
+ * attributes of thing. Mass, time, distance, heat, and angular separation
+ * are among the familiar examples of quantitative properties. Distinct quantities have usually different physical dimensions; although
+ * it is not required nor necessary, for example {@link Torque} and
+ * {@link Energy} have same dimension but are of different nature
+ * (vector for torque, scalar for energy). Note: The Newton-metre ("N·m") is also a way of exressing a Joule (unit
+ * of energy). However, torque is not energy. So, to avoid confusion, we
+ * will use the units "N·m" for torque and not "J". This distinction occurs
+ * due to the scalar nature of energy and the vector nature of torque. Provides quantitative properties or attributes of thing such as
+ mass, time, distance, heat, and angular separation. Each quantity sub-interface holds a static This class represents the units used in expressions to distinguish
+ * between quantities of a different nature but of the same dimensions. Instances of this class are created through the
+ * {@link Unit#alternate(String)} method. This class represents the building blocks on top of which all others
+ * units are created. Base units are typically dimensionally independent.
+ * The actual unit dimension is determinated by the current
+ * {@link Dimension.Model model}. For example using the {@link
+ * Dimension.Model#STANDARD standard} model, {@link SI#CANDELA}
+ * has the dimension of {@link SI#WATT watt}:[code]
+ * // Standard model.
+ * BaseUnit This class represents the "standard base units" which includes SI base
+ * units and possibly others user-defined base units. It does not represent
+ * the base units of any specific {@link SystemOfUnits} (they would have
+ * be base units accross all possible systems otherwise). This class represents the multi-radix units (such as "hour:min:sec").
+ * Instances of this class are created using the {@link Unit#compound
+ * Unit.compound} method. Examples of compound units:[code]
+ * Unit This class identifies the units created by combining or transforming
+ * other units. This class represents the dimension of an unit. Two units Instances of this class are immutable. This class contains units that are not part of the International
+ * System of Units, that is, they are outside the SI, but are important
+ * and widely used.java.math.Context
:[code]
+ * DecimalMeasure extends Measure
_unit;
+
+ /**
+ * Creates a decimal measure for the specified number stated in the
+ * specified unit.
+ */
+ public DecimalMeasure(BigDecimal value, Unit
unit) {
+ _value = value;
+ _unit = unit;
+ }
+
+ /**
+ * Returns the decimal measure for the specified number stated in the
+ * specified unit.
+ *
+ * @param decimal the measurement value.
+ * @param unit the measurement unit.
+ */
+ public static
DecimalMeasure
valueOf(
+ BigDecimal decimal, Unit
unit) {
+ return new DecimalMeasure
(decimal, unit);
+ }
+
+ /**
+ * Returns the decimal measure for the specified textual representation.
+ * This method first reads the
BigDecimal
value, then
+ * the unit if any (value and unit should be separated by white spaces).
+ *
+ * @param csq the decimal measure representation (including unit if any).
+ * @throws NumberFormatException if the specified character sequence is
+ * not a valid representation of decimal measure.
+ */
+ @SuppressWarnings("unchecked")
+ public static DecimalMeasure
valueOf(CharSequence csq) {
+ String str = csq.toString();
+ int numberLength = str.length();
+ int unitStartIndex = -1;
+ for (int i=0; i < str.length(); i++) {
+ if (Character.isWhitespace(str.charAt(i))) {
+ for (int j=i+1; j < str.length(); j++) {
+ if (!Character.isWhitespace(str.charAt(j))) {
+ unitStartIndex = j;
+ break;
+ }
+ }
+ numberLength = i;
+ break;
+ }
+ }
+ BigDecimal decimal = new BigDecimal(str.substring(0, numberLength));
+ Unit unit = Unit.ONE;
+ if (unitStartIndex > 0) {
+ unit = Unit.valueOf(str.substring(unitStartIndex));
+ }
+ return new DecimalMeasure
(decimal, unit);
+ }
+
+ @Override
+ public Unit
getUnit() {
+ return _unit;
+ }
+
+ @Override
+ public BigDecimal getValue() {
+ return _value;
+ }
+
+ /**
+ * Returns the decimal measure equivalent to this measure but stated in the
+ * specified unit. This method will raise an ArithmeticException if the
+ * resulting measure does not have a terminating decimal expansion.
+ *
+ * @param unit the new measurement unit.
+ * @return the measure stated in the specified unit.
+ * @throws ArithmeticException if the converted measure value does not have
+ * a terminating decimal expansion
+ * @see #to(Unit, MathContext)
+ */
+ @Override
+ public DecimalMeasure
to(Unit
unit) {
+ return to(unit, null);
+ }
+
+ /**
+ * Returns the decimal measure equivalent to this measure but stated in the
+ * specified unit, the conversion is performed using the specified math
+ * context.
+ *
+ * @param unit the new measurement unit.
+ * @param mathContext the mathContext used to convert
+ *
BigDecimal
values or null
if none.
+ * @return the measure stated in the specified unit.
+ * @throws ArithmeticException if the result is inexact but the
+ * rounding mode is MathContext.UNNECESSARY
or
+ * mathContext.precision == 0 and the quotient has a
+ * non-terminating decimal expansion.
+ */
+ public DecimalMeasure
to(Unit
unit, MathContext mathContext) {
+ if ((unit == _unit) || (unit.equals(_unit)))
+ return this;
+ UnitConverter cvtr = _unit.getConverterTo(unit);
+ if (cvtr instanceof RationalConverter) {
+ RationalConverter factor = (RationalConverter) cvtr;
+ BigDecimal dividend = BigDecimal.valueOf(factor.getDividend());
+ BigDecimal divisor = BigDecimal.valueOf(factor.getDivisor());
+ BigDecimal result = mathContext == null ?
+ _value.multiply(dividend).divide(divisor) :
+ _value.multiply(dividend, mathContext).divide(divisor, mathContext);
+ return new DecimalMeasure
(result, unit);
+ } else if (cvtr.isLinear()) {
+ BigDecimal factor = BigDecimal.valueOf(cvtr.convert(1.0));
+ BigDecimal result = mathContext == null ?
+ _value.multiply(factor) : _value.multiply(factor, mathContext);
+ return new DecimalMeasure
(result, unit);
+ } else if (cvtr instanceof AddConverter) {
+ BigDecimal offset = BigDecimal.valueOf(((AddConverter)cvtr).getOffset());
+ BigDecimal result = mathContext == null ?
+ _value.add(offset) : _value.add(offset, mathContext);
+ return new DecimalMeasure
(result, unit);
+ } else { // Non-linear and not an offset, convert the double value.
+ BigDecimal result = BigDecimal.valueOf(cvtr.convert(_value.doubleValue()));
+ return new DecimalMeasure
(result, unit);
+ }
+ }
+
+ public double doubleValue(Unit
unit) {
+ if ((unit == _unit) || (unit.equals(_unit)))
+ return _value.doubleValue();
+ return _unit.getConverterTo(unit).convert(_value.doubleValue());
+ }
+
+ private static final long serialVersionUID = 1L;
+}
diff --git a/measure/src/main/java/javax/measure/Measurable.java b/measure/src/main/java/javax/measure/Measurable.java
new file mode 100644
index 00000000..6d632b48
--- /dev/null
+++ b/measure/src/main/java/javax/measure/Measurable.java
@@ -0,0 +1,76 @@
+/*
+ * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
+ * Copyright (C) 2007 - JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software is
+ * freely granted, provided that this notice is preserved.
+ */
+package javax.measure;
+
+import javax.measure.quantity.Quantity;
+import javax.measure.unit.Unit;
+
+/**
+ *
extends Measure
unit) { ... } // Returns median value.
+ * ...
+ * } [/code]
extends Comparable
double
. If the measurable has too great a magnitude to
+ * be represented as a double
, it will be converted to
+ * Double.NEGATIVE_INFINITY
or
+ * Double.POSITIVE_INFINITY
as appropriate.
+ *
+ * @param unit the unit in which this measurable value is stated.
+ * @return the numeric value after conversion to type double
.
+ */
+ double doubleValue(Unit unit);
+
+ /**
+ * Returns the estimated integral value of this measurable stated in
+ * the specified unit as a
long
.
+ *
+ * Number.longValue()
+ * in the sense that the closest integer value is returned
+ * and an ArithmeticException is raised instead
+ * of a bit truncation in case of overflow (safety critical).long
.
+ * @throws ArithmeticException if this quantity cannot be represented
+ * as a long
number in the specified unit.
+ */
+ long longValue(Unit unit) throws ArithmeticException;
+
+}
diff --git a/measure/src/main/java/javax/measure/Measure.java b/measure/src/main/java/javax/measure/Measure.java
new file mode 100644
index 00000000..610727a9
--- /dev/null
+++ b/measure/src/main/java/javax/measure/Measure.java
@@ -0,0 +1,449 @@
+/*
+ * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
+ * Copyright (C) 2007 - JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software is
+ * freely granted, provided that this notice is preserved.
+ */
+package javax.measure;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.math.MathContext;
+
+import javax.measure.quantity.Quantity;
+import javax.measure.unit.CompoundUnit;
+import javax.measure.unit.Unit;
+
+/**
+ *
,
+ Serializable {
+
+ /**
+ * Default constructor.
+ */
+ protected Measure() {
+ }
+
+ /**
+ * Returns the scalar measure for the specified
double
+ * stated in the specified unit.
+ *
+ * @param doubleValue the measurement value.
+ * @param unit the measurement unit.
+ */
+ public static Measure
unit) {
+ return new Double
(doubleValue, unit);
+ }
+
+ /**
+ * Returns the scalar measure for the specified
double
+ * stated in the specified unit.
+ *
+ * @param longValue the measurement value.
+ * @param unit the measurement unit.
+ */
+ public static Measure
unit) {
+ return new Long
(longValue, unit);
+ }
+
+ /**
+ * Returns the scalar measure for the specified
float
+ * stated in the specified unit.
+ *
+ * @param floatValue the measurement value.
+ * @param unit the measurement unit.
+ */
+ public static Measure
unit) {
+ return new Float
(floatValue, unit);
+ }
+
+ /**
+ * Returns the scalar measure for the specified
int
+ * stated in the specified unit.
+ *
+ * @param intValue the measurement value.
+ * @param unit the measurement unit.
+ */
+ public static Measure
unit) {
+ return new Integer
(intValue, unit);
+ }
+
+ /**
+ * Returns the measurement value of this measure.
+ *
+ * @return the measurement value.
+ */
+ public abstract V getValue();
+
+ /**
+ * Returns the measurement unit of this measure.
+ *
+ * @return the measurement unit.
+ */
+ public abstract Unit
getUnit();
+
+ /**
+ * Returns the measure equivalent to this measure but stated in the
+ * specified unit. This method may result in lost of precision
+ * (e.g. measure of integral value).
+ *
+ * @param unit the new measurement unit.
+ * @return the measure stated in the specified unit.
+ */
+ public abstract Measure
unit);
+
+ /**
+ * Returns the value of this measure stated in the specified unit as
+ * a
double
. If the measure has too great a magnitude to
+ * be represented as a double
, it will be converted to
+ * Double.NEGATIVE_INFINITY
or
+ * Double.POSITIVE_INFINITY
as appropriate.
+ *
+ * @param unit the unit in which this measure is stated.
+ * @return the numeric value after conversion to type double
.
+ */
+ public abstract double doubleValue(Unit unit);
+
+ /**
+ * Returns the estimated integral value of this measure stated in
+ * the specified unit as a
long
.
+ *
+ * Number.longValue()
+ * in the sense that the closest integer value is returned
+ * and an ArithmeticException is raised instead
+ * of a bit truncation in case of overflow (safety critical).long
.
+ * @throws ArithmeticException if this quantity cannot be represented
+ * as a long
number in the specified unit.
+ */
+ public long longValue(Unit unit) throws ArithmeticException {
+ double doubleValue = doubleValue(unit);
+ if (java.lang.Double.isNaN(doubleValue)
+ || (doubleValue < java.lang.Long.MIN_VALUE)
+ || (doubleValue > java.lang.Long.MAX_VALUE))
+ throw new ArithmeticException(doubleValue + " " + unit
+ + " cannot be represented as long");
+ return Math.round(doubleValue);
+ }
+
+ /**
+ * Returns the value of this measure stated in the specified unit as a
+ *
float
. If the measure has too great a magnitude to be
+ * represented as a float
, it will be converted to
+ * Float.NEGATIVE_INFINITY
or
+ * Float.POSITIVE_INFINITY
as appropriate.
+ *
+ * @param unit the unit in which the measure is stated.
+ * @return the numeric value after conversion to type float
.
+ */
+ public float floatValue(Unit unit) {
+ return (float) doubleValue(unit);
+ }
+
+ /**
+ * Returns the estimated integral value of this measure stated in
+ * the specified unit as a
int
.
+ *
+ * Number.intValue()
+ * in the sense that the closest integer value is returned
+ * and an ArithmeticException is raised instead
+ * of a bit truncation in case of overflow (safety critical).int
.
+ * @throws ArithmeticException if this quantity cannot be represented
+ * as a int
number in the specified unit.
+ */
+ public int intValue(Unit unit) {
+ long longValue = longValue(unit);
+ if ((longValue > java.lang.Integer.MAX_VALUE)
+ || (longValue < java.lang.Integer.MIN_VALUE))
+ throw new ArithmeticException("Overflow");
+ return (int) longValue;
+ }
+
+ /**
+ * Compares this measure against the specified object for
+ * strict equality (same unit and amount).
+ * To compare measures stated using different units the
+ * {@link #compareTo} method should be used.
+ *
+ * @param obj the object to compare with.
+ * @return
true
if both objects are identical (same
+ * unit and same amount); false
otherwise.
+ */
+ @SuppressWarnings("unchecked")
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Measure))
+ return false;
+ Measure that = (Measure) obj;
+ return this.getUnit().equals(that.getUnit())
+ && this.getValue().equals(that.getValue());
+ }
+
+ /**
+ * Returns the hash code for this scalar.
+ *
+ * @return the hash code value.
+ */
+ public int hashCode() {
+ return getUnit().hashCode() + getValue().hashCode();
+ }
+
+ /**
+ * Returns the String
representation of this measure
+ * The string produced for a given measure is always the same;
+ * it is not affected by locale. This means that it can be used
+ * as a canonical string representation for exchanging data,
+ * or as a key for a Hashtable, etc. Locale-sensitive
+ * measure formatting and parsing is handled by the {@link
+ * MeasureFormat} class and its subclasses.
+ *
+ * @return the string representation of this measure.
+ */
+ public String toString() {
+ if (getUnit() instanceof CompoundUnit)
+ return MeasureFormat.DEFAULT.formatCompound(doubleValue(getUnit()),
+ getUnit(), new StringBuffer(), null).toString();
+ return getValue() + " " + getUnit();
+ }
+
+ /**
+ * Compares this measure to the specified measurable quantity.
+ * This method compares the {@link Measurable#doubleValue(Unit)} of
+ * both this measure and the specified measurable stated in the
+ * same unit (this measure's {@link #getUnit() unit}).
+ *
+ * @return a negative integer, zero, or a positive integer as this measure
+ * is less than, equal to, or greater than the specified measurable
+ * quantity.
+ * @return Double.compare(this.doubleValue(getUnit()),
+ * that.doubleValue(getUnit()))
+ */
+ public int compareTo(Measurable that) {
+ return java.lang.Double.compare(doubleValue(getUnit()), that
+ .doubleValue(getUnit()));
+ }
+
+ /**
+ * Holds scalar implementation for
double
values.
+ */
+ private static final class Double extends
+ Measure
_unit;
+
+ public Double(double value, Unit
unit) {
+ _value = value;
+ _unit = unit;
+ }
+
+ @Override
+ public Unit
getUnit() {
+ return _unit;
+ }
+
+ @Override
+ public java.lang.Double getValue() {
+ return _value;
+ }
+
+ @Override
+ public Measure
unit) {
+ if ((unit == _unit) || (unit.equals(_unit)))
+ return this;
+ return new Double
(doubleValue(unit), unit);
+ }
+
+ public double doubleValue(Unit
unit) {
+ if ((unit == _unit) || (unit.equals(_unit)))
+ return _value;
+ return _unit.getConverterTo(unit).convert(_value);
+ }
+
+ private static final long serialVersionUID = 1L;
+ }
+
+ /**
+ * Holds scalar implementation for
long
values.
+ */
+ private static final class Long extends
+ Measure
_unit;
+
+ public Long(long value, Unit
unit) {
+ _value = value;
+ _unit = unit;
+ }
+
+ @Override
+ public Unit
getUnit() {
+ return _unit;
+ }
+
+ @Override
+ public java.lang.Long getValue() {
+ return _value;
+ }
+
+ @Override
+ public Measure
unit) {
+ if ((unit == _unit) || (unit.equals(_unit)))
+ return this;
+ return new Long
(longValue(unit), unit);
+ }
+
+ public double doubleValue(Unit
unit) {
+ if ((unit == _unit) || (unit.equals(_unit)))
+ return _value;
+ return _unit.getConverterTo(unit).convert(_value);
+ }
+
+ public long longValue(Unit
unit) throws ArithmeticException {
+ if ((unit == _unit) || (unit.equals(_unit)))
+ return _value; // No conversion, returns value directly.
+ return super.longValue(unit);
+ }
+
+ private static final long serialVersionUID = 1L;
+
+ }
+
+ /**
+ * Holds scalar implementation for
float
values.
+ */
+ private static final class Float extends
+ Measure
_unit;
+
+ public Float(float value, Unit
unit) {
+ _value = value;
+ _unit = unit;
+ }
+
+ @Override
+ public Unit
getUnit() {
+ return _unit;
+ }
+
+ @Override
+ public java.lang.Float getValue() {
+ return _value;
+ }
+
+ @Override
+ public Measure
unit) {
+ if ((unit == _unit) || (unit.equals(_unit)))
+ return this;
+ return new Float
(floatValue(unit), unit);
+ }
+
+ public double doubleValue(Unit
unit) {
+ if ((unit == _unit) || (unit.equals(_unit)))
+ return _value;
+ return _unit.getConverterTo(unit).convert(_value);
+ }
+
+ private static final long serialVersionUID = 1L;
+ }
+
+ /**
+ * Holds scalar implementation for
long
values.
+ */
+ private static final class Integer extends
+ Measure
_unit;
+
+ public Integer(int value, Unit
unit) {
+ _value = value;
+ _unit = unit;
+ }
+
+ @Override
+ public Unit
getUnit() {
+ return _unit;
+ }
+
+ @Override
+ public java.lang.Integer getValue() {
+ return _value;
+ }
+
+ @Override
+ public Measure
unit) {
+ if ((unit == _unit) || (unit.equals(_unit)))
+ return this;
+ return new Integer
(intValue(unit), unit);
+ }
+
+ public double doubleValue(Unit
unit) {
+ if ((unit == _unit) || (unit.equals(_unit)))
+ return _value;
+ return _unit.getConverterTo(unit).convert(_value);
+ }
+
+ public long longValue(Unit
unit) throws ArithmeticException {
+ if ((unit == _unit) || (unit.equals(_unit)))
+ return _value; // No conversion, returns value directly.
+ return super.longValue(unit);
+ }
+
+ private static final long serialVersionUID = 1L;
+
+ }
+
+ /**
+ * @deprecated {@link DecimalMeasure} should be used directly.
+ */
+ public static
Measure
unit) {
+ return DecimalMeasure.valueOf(decimal, unit);
+ }
+
+ /**
+ * @deprecated {@link DecimalMeasure} should be used directly and
+ *
MathContext
specified explicitly when
+ * {@link DecimalMeasure#to(Unit, MathContext) converting}.
+ */
+ public static Measure
unit, MathContext mathContext) {
+ return DecimalMeasure.valueOf(decimal, unit);
+ }
+
+ /**
+ * @deprecated {@link VectorMeasure} should be used directly.
+ */
+ public static
Measure
unit) {
+ return VectorMeasure.valueOf(components, unit);
+ }
+}
\ No newline at end of file
diff --git a/measure/src/main/java/javax/measure/MeasureFormat.java b/measure/src/main/java/javax/measure/MeasureFormat.java
new file mode 100644
index 00000000..cd6bb68a
--- /dev/null
+++ b/measure/src/main/java/javax/measure/MeasureFormat.java
@@ -0,0 +1,169 @@
+/*
+ * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
+ * Copyright (C) 2007 - JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software is
+ * freely granted, provided that this notice is preserved.
+ */
+package javax.measure;
+
+import java.math.BigDecimal;
+import java.text.FieldPosition;
+import java.text.Format;
+import java.text.NumberFormat;
+import java.text.ParseException;
+import java.text.ParsePosition;
+
+import javax.measure.unit.CompoundUnit;
+import javax.measure.unit.Unit;
+import javax.measure.unit.UnitFormat;
+
+/**
+ *
getInstance(Number.getInstance(), Unit.getInstance())
+ */
+ public static MeasureFormat getInstance() {
+ return DEFAULT;
+ }
+
+ static final NumberUnit DEFAULT = new NumberUnit(NumberFormat
+ .getInstance(), UnitFormat.getInstance());
+
+ /**
+ * Returns the measure format using the specified number format and
+ * unit format (the number and unit are separated by a space).
+ *
+ * @param numberFormat the number format.
+ * @param unitFormat the unit format.
+ * @return the corresponding format.
+ */
+ public static MeasureFormat getInstance(NumberFormat numberFormat,
+ UnitFormat unitFormat) {
+ return new NumberUnit(numberFormat, unitFormat);
+ }
+
+ // Holds default implementation.
+ static final class NumberUnit extends MeasureFormat {
+ private final NumberFormat _numberFormat;
+
+ private final UnitFormat _unitFormat;
+
+ private NumberUnit(NumberFormat numberFormat, UnitFormat unitFormat) {
+ _numberFormat = numberFormat;
+ _unitFormat = unitFormat;
+ }
+
+ @Override
+ public StringBuffer format(Object obj, StringBuffer toAppendTo,
+ FieldPosition pos) {
+ Measure, ?> measure = (Measure, ?>) obj;
+ Object value = measure.getValue();
+ Unit> unit = measure.getUnit();
+ if (value instanceof Number) {
+ if (unit instanceof CompoundUnit)
+ return formatCompound(((Number) value).doubleValue(),
+ (CompoundUnit>) unit, toAppendTo, pos);
+ _numberFormat.format(value, toAppendTo, pos);
+ } else {
+ toAppendTo.append(value);
+ }
+ if (!measure.getUnit().equals(Unit.ONE)) {
+ toAppendTo.append(' ');
+ _unitFormat.format(unit, toAppendTo, pos);
+ }
+ return toAppendTo;
+ }
+
+ // Measure using Compound unit have no separators in their representation.
+ StringBuffer formatCompound(double value, Unit> unit,
+ StringBuffer toAppendTo, FieldPosition pos) {
+ if (!(unit instanceof CompoundUnit)) {
+ toAppendTo.append((long) value);
+ return _unitFormat.format(unit, toAppendTo, pos);
+ }
+ Unit> high = ((CompoundUnit>) unit).getHigher();
+ Unit> low = ((CompoundUnit>) unit).getLower(); // The unit in which the value is stated.
+ long highValue = (long) low.getConverterTo(high).convert(value);
+ double lowValue = value
+ - high.getConverterTo(low).convert(highValue);
+ formatCompound(highValue, high, toAppendTo, pos);
+ formatCompound(lowValue, low, toAppendTo, pos);
+ return toAppendTo;
+ }
+
+ @Override
+ public Object parseObject(String source, ParsePosition pos) {
+ int start = pos.getIndex();
+ try {
+ int i = start;
+ Number value = _numberFormat.parse(source, pos);
+ if (i == pos.getIndex())
+ return null; // Cannot parse.
+ i = pos.getIndex();
+ if (i >= source.length())
+ return measureOf(value, Unit.ONE); // No unit.
+ boolean isCompound = !Character.isWhitespace(source.charAt(i));
+ if (isCompound)
+ return parseCompound(value, source, pos);
+ if (++i >= source.length())
+ return measureOf(value, Unit.ONE); // No unit.
+ pos.setIndex(i); // Skips separator.
+ Unit> unit = _unitFormat.parseProductUnit(source, pos);
+ return measureOf(value, unit);
+ } catch (ParseException e) {
+ pos.setIndex(start);
+ pos.setErrorIndex(e.getErrorOffset());
+ return null;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private Object parseCompound(Number highValue, String source,
+ ParsePosition pos) throws ParseException {
+ Unit high = _unitFormat.parseSingleUnit(source, pos);
+ int i = pos.getIndex();
+ if (i >= source.length()
+ || Character.isWhitespace(source.charAt(i)))
+ return measureOf(highValue, high);
+ Measure lowMeasure = (Measure) parseObject(source, pos);
+ Unit unit = lowMeasure.getUnit();
+ long l = lowMeasure.longValue(unit)
+ + (long) high.getConverterTo(unit).convert(
+ highValue.longValue());
+ return Measure.valueOf(l, unit);
+ }
+
+ @SuppressWarnings("unchecked")
+ private static Measure measureOf(Number value, Unit unit) {
+ if (value instanceof Double) {
+ return Measure.valueOf(value.doubleValue(), unit);
+ } else if (value instanceof Long) {
+ return Measure.valueOf(value.longValue(), unit);
+ } else if (value instanceof Float) {
+ return Measure.valueOf(value.floatValue(), unit);
+ } else if (value instanceof Integer) {
+ return Measure.valueOf(value.intValue(), unit);
+ } else if (value instanceof BigDecimal) {
+ return DecimalMeasure.valueOf((BigDecimal) value, unit);
+ } else {
+ return Measure.valueOf(value.doubleValue(), unit);
+ }
+ }
+
+ private static final long serialVersionUID = 1L;
+ }
+}
diff --git a/measure/src/main/java/javax/measure/VectorMeasure.java b/measure/src/main/java/javax/measure/VectorMeasure.java
new file mode 100644
index 00000000..1fd4f322
--- /dev/null
+++ b/measure/src/main/java/javax/measure/VectorMeasure.java
@@ -0,0 +1,273 @@
+/*
+ * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
+ * Copyright (C) 2007 - JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software is
+ * freely granted, provided that this notice is preserved.
+ */
+package javax.measure;
+
+import javax.measure.converter.UnitConverter;
+import javax.measure.quantity.Quantity;
+import javax.measure.unit.CompoundUnit;
+import javax.measure.unit.Unit;
+
+/**
+ * extends Measure
VectorMeasure
valueOf(
+ double x, double y, Unit
unit) {
+ return new TwoDimensional
(x, y, unit);
+ }
+
+ /**
+ * Returns a 3-dimensional measurement vector.
+ *
+ * @param x the first vector component value.
+ * @param y the second vector component value.
+ * @param z the third vector component value.
+ * @param unit the measurement unit.
+ */
+ public static
VectorMeasure
valueOf(
+ double x, double y, double z, Unit
unit) {
+ return new ThreeDimensional
(x, y, z, unit);
+ }
+
+ /**
+ * Returns a multi-dimensional measurement vector.
+ *
+ * @param components the vector component values.
+ * @param unit the measurement unit.
+ */
+ public static
VectorMeasure
valueOf(double[] components,
+ Unit
unit) {
+ return new MultiDimensional
(components, unit);
+ }
+
+ /**
+ * Returns the measurement vector equivalent to this one but stated in the
+ * specified unit.
+ *
+ * @param unit the new measurement unit.
+ * @return the vector measure stated in the specified unit.
+ */
+ public abstract VectorMeasure
to(Unit
unit);
+
+ /**
+ * Returns the norm of this measurement vector stated in the specified
+ * unit.
+ *
+ * @param unit the unit in which the norm is stated.
+ * @return
|this|
+ */
+ public abstract double doubleValue(Unit unit);
+
+ /**
+ * Returns the
String
representation of this measurement
+ * vector (for example [2.3 m/s, 5.6 m/s]
).
+ *
+ * @return the textual representation of the measurement vector.
+ */
+ public String toString() {
+ double[] values = getValue();
+ Unit unit = getUnit();
+ StringBuffer tmp = new StringBuffer();
+ tmp.append('[');
+ for (double v : values) {
+ if (tmp.length() > 1) {
+ tmp.append(", ");
+ }
+ if (unit instanceof CompoundUnit) {
+ MeasureFormat.DEFAULT.formatCompound(v, unit, tmp, null);
+ } else {
+ tmp.append(v).append(" ").append(unit);
+ }
+ }
+ tmp.append("] ");
+ return tmp.toString();
+ }
+
+ // Holds 2-dimensional implementation.
+ private static class TwoDimensional
extends VectorMeasure
{
+
+ private final double _x;
+
+ private final double _y;
+
+ private final Unit
_unit;
+
+ private TwoDimensional(double x, double y, Unit
unit) {
+ _x = x;
+ _y = y;
+ _unit = unit;
+
+ }
+ @Override
+ public double doubleValue(Unit
unit) {
+ double norm = Math.sqrt(_x * _x + _y * _y);
+ if ((unit == _unit) || (unit.equals(_unit)))
+ return norm;
+ return _unit.getConverterTo(unit).convert(norm);
+ }
+
+ @Override
+ public Unit
getUnit() {
+ return _unit;
+ }
+
+ @Override
+ public double[] getValue() {
+ return new double[] { _x, _y };
+ }
+
+ @Override
+ public TwoDimensional
to(Unit
unit) {
+ if ((unit == _unit) || (unit.equals(_unit)))
+ return this;
+ UnitConverter cvtr = _unit.getConverterTo(unit);
+ return new TwoDimensional
(cvtr.convert(_x), cvtr.convert(_y), unit);
+ }
+
+ private static final long serialVersionUID = 1L;
+
+ }
+
+ // Holds 3-dimensional implementation.
+ private static class ThreeDimensional
extends VectorMeasure
{
+
+ private final double _x;
+
+ private final double _y;
+
+ private final double _z;
+
+ private final Unit
_unit;
+
+ private ThreeDimensional(double x, double y, double z, Unit
unit) {
+ _x = x;
+ _y = y;
+ _z = z;
+ _unit = unit;
+
+ }
+ @Override
+ public double doubleValue(Unit
unit) {
+ double norm = Math.sqrt(_x * _x + _y * _y + _z * _z);
+ if ((unit == _unit) || (unit.equals(_unit)))
+ return norm;
+ return _unit.getConverterTo(unit).convert(norm);
+ }
+
+ @Override
+ public Unit
getUnit() {
+ return _unit;
+ }
+
+ @Override
+ public double[] getValue() {
+ return new double[] { _x, _y, _z };
+ }
+
+ @Override
+ public ThreeDimensional
to(Unit
unit) {
+ if ((unit == _unit) || (unit.equals(_unit)))
+ return this;
+ UnitConverter cvtr = _unit.getConverterTo(unit);
+ return new ThreeDimensional
(cvtr.convert(_x), cvtr.convert(_y), cvtr.convert(_z), unit);
+ }
+
+ private static final long serialVersionUID = 1L;
+
+ }
+ // Holds multi-dimensional implementation.
+ private static class MultiDimensional
extends VectorMeasure
{
+
+ private final double[] _components;
+
+ private final Unit
_unit;
+
+ private MultiDimensional(double[] components, Unit
unit) {
+ _components = components.clone();
+ _unit = unit;
+ }
+
+ @Override
+ public double doubleValue(Unit
unit) {
+ double normSquare = _components[0] * _components[0];
+ for (int i=1, n=_components.length; i < n;) {
+ double d = _components[i++];
+ normSquare += d * d;
+ }
+ if ((unit == _unit) || (unit.equals(_unit)))
+ return Math.sqrt(normSquare);
+ return _unit.getConverterTo(unit).convert(Math.sqrt(normSquare));
+ }
+
+ @Override
+ public Unit
getUnit() {
+ return _unit;
+ }
+
+ @Override
+ public double[] getValue() {
+ return _components.clone();
+ }
+
+ @Override
+ public MultiDimensional
to(Unit
unit) {
+ if ((unit == _unit) || (unit.equals(_unit)))
+ return this;
+ UnitConverter cvtr = _unit.getConverterTo(unit);
+ double[] newValues = new double[_components.length];
+ for (int i=0; i < _components.length; i++) {
+ newValues[i] = cvtr.convert(_components[i]);
+ }
+ return new MultiDimensional
(newValues, unit);
+ }
+
+ private static final long serialVersionUID = 1L;
+
+ }
+}
diff --git a/measure/src/main/java/javax/measure/converter/AddConverter.java b/measure/src/main/java/javax/measure/converter/AddConverter.java
new file mode 100644
index 00000000..2c0b8d35
--- /dev/null
+++ b/measure/src/main/java/javax/measure/converter/AddConverter.java
@@ -0,0 +1,80 @@
+/*
+ * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
+ * Copyright (C) 2006 - JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software is
+ * freely granted, provided that this notice is preserved.
+ */
+package javax.measure.converter;
+
+
+/**
+ *
double
) to numeric values.ConversionException
with no detail message.
+ */
+ public ConversionException() {
+ super();
+ }
+
+ /**
+ * Constructs a ConversionException
with the specified detail
+ * message.
+ *
+ * @param message the detail message.
+ */
+ public ConversionException(String message) {
+ super(message);
+ }
+
+ private static final long serialVersionUID = 1L;
+}
\ No newline at end of file
diff --git a/measure/src/main/java/javax/measure/converter/LogConverter.java b/measure/src/main/java/javax/measure/converter/LogConverter.java
new file mode 100644
index 00000000..f10c30b9
--- /dev/null
+++ b/measure/src/main/java/javax/measure/converter/LogConverter.java
@@ -0,0 +1,107 @@
+/*
+ * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
+ * Copyright (C) 2006 - JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software is
+ * freely granted, provided that this notice is preserved.
+ */
+package javax.measure.converter;
+
+/**
+ * Math.E
for
+ * the Natural Logarithm).
+ */
+ public LogConverter(double base) {
+ _base = base;
+ _logBase = Math.log(base);
+ _invLogBase = 1.0 / _logBase;
+ }
+
+ /**
+ * Returns the logarithmic base of this converter.
+ *
+ * @return the logarithmic base (e.g. Math.E
for
+ * the Natural Logarithm).
+ */
+ public double getBase() {
+ return _base;
+ }
+
+ @Override
+ public UnitConverter inverse() {
+ return _inverse;
+ }
+
+ @Override
+ public double convert(double amount) {
+ return _invLogBase * Math.log(amount);
+ }
+
+ @Override
+ public boolean isLinear() {
+ return false;
+ }
+
+ /**
+ * This inner class represents the inverse of the logarithmic converter
+ * (exponentiation converter).
+ */
+ private class Inverse extends UnitConverter {
+
+
+ @Override
+ public UnitConverter inverse() {
+ return LogConverter.this;
+ }
+
+ @Override
+ public double convert(double amount) {
+ return Math.exp(_logBase * amount);
+ }
+
+ @Override
+ public boolean isLinear() {
+ return false;
+ }
+
+ private static final long serialVersionUID = 1L;
+ }
+
+ private static final long serialVersionUID = 1L;
+}
\ No newline at end of file
diff --git a/measure/src/main/java/javax/measure/converter/MultiplyConverter.java b/measure/src/main/java/javax/measure/converter/MultiplyConverter.java
new file mode 100644
index 00000000..2dfa32af
--- /dev/null
+++ b/measure/src/main/java/javax/measure/converter/MultiplyConverter.java
@@ -0,0 +1,86 @@
+/*
+ * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
+ * Copyright (C) 2006 - JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software is
+ * freely granted, provided that this notice is preserved.
+ */
+package javax.measure.converter;
+
+/**
+ * double
).
+ * For exact scaling conversions {@link RationalConverter} is preferred.long
numbers).divisor < 0
+ * @throws IllegalArgumentException if dividend == divisor
+ */
+ public RationalConverter(long dividend, long divisor) {
+ if (divisor < 0)
+ throw new IllegalArgumentException("Negative divisor");
+ if (dividend == divisor)
+ throw new IllegalArgumentException("Identity converter not allowed");
+ _dividend = dividend;
+ _divisor = divisor;
+ }
+
+ /**
+ * Returns the dividend for this rational converter.
+ *
+ * @return this converter dividend.
+ */
+ public long getDividend() {
+ return _dividend;
+ }
+
+ /**
+ * Returns the positive divisor for this rational converter.
+ *
+ * @return this converter divisor.
+ */
+ public long getDivisor() {
+ return _divisor;
+ }
+
+ @Override
+ public UnitConverter inverse() {
+ return _dividend < 0 ? new RationalConverter(-_divisor, -_dividend)
+ : new RationalConverter(_divisor, _dividend);
+ }
+
+ @Override
+ public double convert(double amount) {
+ return amount * _dividend / _divisor;
+ }
+
+ @Override
+ public boolean isLinear() {
+ return true;
+ }
+
+ @Override
+ public UnitConverter concatenate(UnitConverter converter) {
+ if (converter instanceof RationalConverter) {
+ RationalConverter that = (RationalConverter) converter;
+ long dividendLong = this._dividend * that._dividend;
+ long divisorLong = this._divisor * that._divisor;
+ double dividendDouble = ((double)this._dividend) * that._dividend;
+ double divisorDouble = ((double)this._divisor) * that._divisor;
+ if ((dividendLong != dividendDouble) ||
+ (divisorLong != divisorDouble)) { // Long overflows.
+ return new MultiplyConverter(dividendDouble / divisorDouble);
+ }
+ long gcd = gcd(dividendLong, divisorLong);
+ return RationalConverter.valueOf(dividendLong / gcd, divisorLong / gcd);
+ } else if (converter instanceof MultiplyConverter) {
+ return converter.concatenate(this);
+ } else {
+ return super.concatenate(converter);
+ }
+ }
+
+ private static UnitConverter valueOf(long dividend, long divisor) {
+ return (dividend == 1L) && (divisor == 1L) ? UnitConverter.IDENTITY
+ : new RationalConverter(dividend, divisor);
+ }
+
+ /**
+ * Returns the greatest common divisor (Euclid's algorithm).
+ *
+ * @param m the first number.
+ * @param nn the second number.
+ * @return the greatest common divisor.
+ */
+ private static long gcd(long m, long n) {
+ if (n == 0L) {
+ return m;
+ } else {
+ return gcd(n, m % n);
+ }
+ }
+
+ private static final long serialVersionUID = 1L;
+}
\ No newline at end of file
diff --git a/measure/src/main/java/javax/measure/converter/UnitConverter.java b/measure/src/main/java/javax/measure/converter/UnitConverter.java
new file mode 100644
index 00000000..03dcd05e
--- /dev/null
+++ b/measure/src/main/java/javax/measure/converter/UnitConverter.java
@@ -0,0 +1,188 @@
+/*
+ * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
+ * Copyright (C) 2006 - JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software is
+ * freely granted, provided that this notice is preserved.
+ */
+package javax.measure.converter;
+
+import java.io.Serializable;
+
+/**
+ * ONE.convert(x) == x
).
+ */
+ public static final UnitConverter IDENTITY = new Identity();
+
+ /**
+ * Default constructor.
+ */
+ protected UnitConverter() {
+ }
+
+ /**
+ * Returns the inverse of this converter. If x
is a valid
+ * value, then x == inverse().convert(convert(x))
to within
+ * the accuracy of computer arithmetic.
+ *
+ * @return the inverse of this converter.
+ */
+ public abstract UnitConverter inverse();
+
+ /**
+ * Converts a double value.
+ *
+ * @param x the numeric value to convert.
+ * @return the converted numeric value.
+ * @throws ConversionException if an error occurs during conversion.
+ */
+ public abstract double convert(double x) throws ConversionException;
+
+ /**
+ * Indicates if this converter is linear. A converter is linear if
+ * convert(u + v) == convert(u) + convert(v)
and
+ * convert(r * u) == r * convert(u)
.
+ * For linear converters the following property always hold:[code]
+ * y1 = c1.convert(x1);
+ * y2 = c2.convert(x2);
+ * then y1*y2 = c1.concatenate(c2).convert(x1*x2)[/code]
+ *
+ * @return true
if this converter is linear;
+ * false
otherwise.
+ */
+ public abstract boolean isLinear();
+
+ /**
+ * Indicates whether this converter is considered the same as the
+ * converter specified. To be considered equal this converter
+ * concatenated with the one specified must returns the {@link #IDENTITY}.
+ *
+ * @param cvtr the converter with which to compare.
+ * @return true
if the specified object is a converter
+ * considered equals to this converter;false
otherwise.
+ */
+ public boolean equals(Object cvtr) {
+ if (!(cvtr instanceof UnitConverter)) return false;
+ return this.concatenate(((UnitConverter)cvtr).inverse()) == IDENTITY;
+ }
+
+ /**
+ * Returns a hash code value for this converter. Equals object have equal
+ * hash codes.
+ *
+ * @return this converter hash code value.
+ * @see #equals
+ */
+ public int hashCode() {
+ return Float.floatToIntBits((float)convert(1.0));
+ }
+
+ /**
+ * Concatenates this converter with another converter. The resulting
+ * converter is equivalent to first converting by the specified converter,
+ * and then converting by this converter.
+ *
+ * UML Diagram
+
+
\ No newline at end of file
diff --git a/measure/src/main/java/javax/measure/package.html b/measure/src/main/java/javax/measure/package.html
new file mode 100644
index 00000000..3579c941
--- /dev/null
+++ b/measure/src/main/java/javax/measure/package.html
@@ -0,0 +1,77 @@
+
+
+ Using measures there is no room for error:[code]
+ class Person {
+ void setWeight(Measurable extends Measure
extends Measurable
{
+ public Amount(double value, double error, Unit
unit) { ... }
+ public Amount
plus(Amount
that) {...}
+ public Amount> times(Amount> that) {...}
+ ... // doubleValue(Unit) returns estimated value.
+ }
+ [/code]
UNIT
field
+ holding the standard unit for the quantity. extends DerivedUnit
{
+
+ /**
+ * Holds the symbol.
+ */
+ private final String _symbol;
+
+ /**
+ * Holds the parent unit (a system unit).
+ */
+ private final Unit> _parent;
+
+ /**
+ * Creates an alternate unit for the specified unit identified by the
+ * specified symbol.
+ *
+ * @param symbol the symbol for this alternate unit.
+ * @param parent the system unit from which this alternate unit is
+ * derived.
+ * @throws UnsupportedOperationException if the source is not
+ * a standard unit.
+ * @throws IllegalArgumentException if the specified symbol is
+ * associated to a different unit.
+ */
+ AlternateUnit(String symbol, Unit> parent) {
+ if (!parent.isStandardUnit())
+ throw new UnsupportedOperationException(this
+ + " is not a standard unit");
+ _symbol = symbol;
+ _parent = parent;
+ // Checks if the symbol is associated to a different unit.
+ synchronized (Unit.SYMBOL_TO_UNIT) {
+ Unit> unit = Unit.SYMBOL_TO_UNIT.get(symbol);
+ if (unit == null) {
+ Unit.SYMBOL_TO_UNIT.put(symbol, this);
+ return;
+ }
+ if (unit instanceof AlternateUnit) {
+ AlternateUnit> existingUnit = (AlternateUnit>) unit;
+ if (symbol.equals(existingUnit._symbol)
+ && _parent.equals(existingUnit._parent))
+ return; // OK, same unit.
+ }
+ throw new IllegalArgumentException("Symbol " + symbol
+ + " is associated to a different unit");
+ }
+ }
+
+ /**
+ * Returns the symbol for this alternate unit.
+ *
+ * @return this alternate unit symbol.
+ */
+ public final String getSymbol() {
+ return _symbol;
+ }
+
+ /**
+ * Returns the parent unit from which this alternate unit is derived
+ * (a system unit itself).
+ *
+ * @return the parent of the alternate unit.
+ */
+ @SuppressWarnings("unchecked")
+ public final Unit super Q> getParent() {
+ return (Unit super Q>) _parent;
+ }
+
+ @Override
+ public final Unit super Q> getStandardUnit() {
+ return this;
+ }
+
+ @Override
+ public final UnitConverter toStandardUnit() {
+ return UnitConverter.IDENTITY;
+ }
+
+ /**
+ * Indicates if this alternate unit is considered equals to the specified
+ * object (both are alternate units with equal symbol, equal base units
+ * and equal converter to base units).
+ *
+ * @param that the object to compare for equality.
+ * @return
true
if this
and that
+ * are considered equals; false
otherwise.
+ */
+ public boolean equals(Object that) {
+ if (this == that)
+ return true;
+ if (!(that instanceof AlternateUnit))
+ return false;
+ AlternateUnit> thatUnit = (AlternateUnit>) that;
+ return this._symbol.equals(thatUnit._symbol); // Symbols are unique.
+ }
+
+ // Implements abstract method.
+ public int hashCode() {
+ return _symbol.hashCode();
+ }
+
+ private static final long serialVersionUID = 1L;
+}
\ No newline at end of file
diff --git a/measure/src/main/java/javax/measure/unit/BaseUnit.java b/measure/src/main/java/javax/measure/unit/BaseUnit.java
new file mode 100644
index 00000000..96403b83
--- /dev/null
+++ b/measure/src/main/java/javax/measure/unit/BaseUnit.java
@@ -0,0 +1,112 @@
+/*
+ * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
+ * Copyright (C) 2006 - JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software is
+ * freely granted, provided that this notice is preserved.
+ */
+package javax.measure.unit;
+
+import javax.measure.converter.UnitConverter;
+import javax.measure.quantity.Quantity;
+
+/**
+ * extends Unit
{
+
+ /**
+ * Holds the symbol.
+ */
+ private final String _symbol;
+
+ /**
+ * Creates a base unit having the specified symbol.
+ *
+ * @param symbol the symbol of this base unit.
+ * @throws IllegalArgumentException if the specified symbol is
+ * associated to a different unit.
+ */
+ public BaseUnit(String symbol) {
+ _symbol = symbol;
+ // Checks if the symbol is associated to a different unit.
+ synchronized (Unit.SYMBOL_TO_UNIT) {
+ Unit> unit = Unit.SYMBOL_TO_UNIT.get(symbol);
+ if (unit == null) {
+ Unit.SYMBOL_TO_UNIT.put(symbol, this);
+ return;
+ }
+ if (!(unit instanceof BaseUnit))
+ throw new IllegalArgumentException("Symbol " + symbol
+ + " is associated to a different unit");
+ }
+ }
+
+ /**
+ * Returns the unique symbol for this base unit.
+ *
+ * @return this base unit symbol.
+ */
+ public final String getSymbol() {
+ return _symbol;
+ }
+
+ /**
+ * Indicates if this base unit is considered equals to the specified
+ * object (both are base units with equal symbol, standard dimension and
+ * standard transform).
+ *
+ * @param that the object to compare for equality.
+ * @return
true
if this
and that
+ * are considered equals; false
otherwise.
+ */
+ public boolean equals(Object that) {
+ if (this == that)
+ return true;
+ if (!(that instanceof BaseUnit))
+ return false;
+ BaseUnit> thatUnit = (BaseUnit>) that;
+ return this._symbol.equals(thatUnit._symbol);
+ }
+
+ @Override
+ public int hashCode() {
+ return _symbol.hashCode();
+ }
+
+ @Override
+ public Unit super Q> getStandardUnit() {
+ return this;
+ }
+
+ @Override
+ public UnitConverter toStandardUnit() {
+ return UnitConverter.IDENTITY;
+ }
+
+ private static final long serialVersionUID = 1L;
+}
\ No newline at end of file
diff --git a/measure/src/main/java/javax/measure/unit/CompoundUnit.java b/measure/src/main/java/javax/measure/unit/CompoundUnit.java
new file mode 100644
index 00000000..82bc88dd
--- /dev/null
+++ b/measure/src/main/java/javax/measure/unit/CompoundUnit.java
@@ -0,0 +1,109 @@
+/*
+ * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
+ * Copyright (C) 2006 - JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software is
+ * freely granted, provided that this notice is preserved.
+ */
+package javax.measure.unit;
+
+import javax.measure.converter.UnitConverter;
+import javax.measure.quantity.Quantity;
+
+/**
+ * extends DerivedUnit
{
+
+ /**
+ * Holds the higher unit.
+ */
+ private final Unit
_high;
+
+ /**
+ * Holds the lower unit.
+ */
+ private final Unit
_low;
+
+ /**
+ * Creates a compound unit from the specified units.
+ *
+ * @param high the high unit.
+ * @param low the lower unit(s)
+ * @throws IllegalArgumentException if both units do not the same system
+ * unit.
+ */
+ CompoundUnit(Unit
high, Unit
low) {
+ if (!high.getStandardUnit().equals(low.getStandardUnit()))
+ throw new IllegalArgumentException(
+ "Both units do not have the same system unit");
+ _high = high;
+ _low = low;
+
+ }
+
+ /**
+ * Returns the lower unit of this compound unit.
+ *
+ * @return the lower unit.
+ */
+ public Unit
getLower() {
+ return _low;
+ }
+
+ /**
+ * Returns the higher unit of this compound unit.
+ *
+ * @return the higher unit.
+ */
+ public Unit
getHigher() {
+ return _high;
+ }
+
+ /**
+ * Indicates if this compound unit is considered equals to the specified
+ * object (both are compound units with same composing units in the
+ * same order).
+ *
+ * @param that the object to compare for equality.
+ * @return
true
if this
and that
+ * are considered equals; false
otherwise.
+ */
+ public boolean equals(Object that) {
+ if (this == that)
+ return true;
+ if (!(that instanceof CompoundUnit))
+ return false;
+ CompoundUnit> thatUnit = (CompoundUnit>) that;
+ return this._high.equals(thatUnit._high)
+ && this._low.equals(thatUnit._low);
+ }
+
+ @Override
+ public int hashCode() {
+ return _high.hashCode() ^ _low.hashCode();
+ }
+
+ @Override
+ public Unit super Q> getStandardUnit() {
+ return _low.getStandardUnit();
+ }
+
+ @Override
+ public UnitConverter toStandardUnit() {
+ return _low.toStandardUnit();
+ }
+
+ private static final long serialVersionUID = 1L;
+}
\ No newline at end of file
diff --git a/measure/src/main/java/javax/measure/unit/DerivedUnit.java b/measure/src/main/java/javax/measure/unit/DerivedUnit.java
new file mode 100644
index 00000000..5dd1d51f
--- /dev/null
+++ b/measure/src/main/java/javax/measure/unit/DerivedUnit.java
@@ -0,0 +1,27 @@
+/*
+ * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
+ * Copyright (C) 2006 - JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software is
+ * freely granted, provided that this notice is preserved.
+ */
+package javax.measure.unit;
+
+import javax.measure.quantity.Quantity;
+
+/**
+ * extends Unit
{
+
+ /**
+ * Default constructor.
+ */
+ protected DerivedUnit() {
+ }
+}
\ No newline at end of file
diff --git a/measure/src/main/java/javax/measure/unit/Dimension.java b/measure/src/main/java/javax/measure/unit/Dimension.java
new file mode 100644
index 00000000..094f22d8
--- /dev/null
+++ b/measure/src/main/java/javax/measure/unit/Dimension.java
@@ -0,0 +1,259 @@
+/*
+ * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
+ * Copyright (C) 2006 - JScience (http://jscience.org/)
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software is
+ * freely granted, provided that this notice is preserved.
+ */
+package javax.measure.unit;
+
+import java.io.Serializable;
+
+import javax.measure.converter.RationalConverter;
+import javax.measure.converter.UnitConverter;
+import javax.measure.quantity.Dimensionless;
+
+/**
+ *
u1
+ * and u2
are {@link Unit#isCompatible compatible} if and
+ * only if (u1.getDimension().equals(u2.getDimension())))
+ * this * that
+ */
+ public final Dimension times(Dimension that) {
+ return new Dimension(this._pseudoUnit.times(that._pseudoUnit));
+ }
+
+ /**
+ * Returns the quotient of this dimension with the one specified.
+ *
+ * @param that the dimension divisor.
+ * @return this / that
+ */
+ public final Dimension divide(Dimension that) {
+ return new Dimension(this._pseudoUnit.divide(that._pseudoUnit));
+ }
+
+ /**
+ * Returns this dimension raised to an exponent.
+ *
+ * @param n the exponent.
+ * @return the result of raising this dimension to the exponent.
+ */
+ public final Dimension pow(int n) {
+ return new Dimension(this._pseudoUnit.pow(n));
+ }
+
+ /**
+ * Returns the given root of this dimension.
+ *
+ * @param n the root's order.
+ * @return the result of taking the given root of this dimension.
+ * @throws ArithmeticException if n == 0
.
+ */
+ public final Dimension root(int n) {
+ return new Dimension(this._pseudoUnit.root(n));
+ }
+
+ /**
+ * Returns the representation of this dimension.
+ *
+ * @return the representation of this dimension.
+ */
+ public String toString() {
+ return _pseudoUnit.toString();
+ }
+
+ /**
+ * Indicates if the specified dimension is equals to the one specified.
+ *
+ * @param that the object to compare to.
+ * @return true
if this dimension is equals to that dimension;
+ * false
otherwise.
+ */
+ public boolean equals(Object that) {
+ if (this == that)
+ return true;
+ return (that instanceof Dimension)
+ && _pseudoUnit.equals(((Dimension) that)._pseudoUnit);
+ }
+
+ /**
+ * Returns the hash code for this dimension.
+ *
+ * @return this dimension hashcode value.
+ */
+ public int hashCode() {
+ return _pseudoUnit.hashCode();
+ }
+
+ /**
+ * Sets the model used to determinate the units dimensions.
+ *
+ * @param model the new model to be used when calculating unit dimensions.
+ */
+ public static void setModel(Model model) {
+ Dimension.CurrentModel = model;
+ }
+
+ /**
+ * Returns the model used to determinate the units dimensions
+ * (default {@link Model#STANDARD STANDARD}).
+ *
+ * @return the model used when calculating unit dimensions.
+ */
+ public static Model getModel() {
+ return Dimension.CurrentModel;
+ }
+
+ /**
+ * This interface represents the mapping between {@link BaseUnit base units}
+ * and {@link Dimension dimensions}. Custom models may allow
+ * conversions not possible using the {@link #STANDARD standard} model.
+ * For example:[code]
+ * public static void main(String[] args) {
+ * Dimension.Model relativistic = new Dimension.Model() {
+ * RationalConverter meterToSecond = new RationalConverter(1, 299792458); // 1/c
+ *
+ * public Dimension getDimension(BaseUnit unit) {
+ * if (unit.equals(SI.METER)) return Dimension.TIME;
+ * return Dimension.Model.STANDARD.getDimension(unit);
+ * }
+ *
+ * public UnitConverter getTransform(BaseUnit unit) {
+ * if (unit.equals(SI.METER)) return meterToSecond;
+ * return Dimension.Model.STANDARD.getTransform(unit);
+ * }};
+ * Dimension.setModel(relativistic);
+ *
+ * // Converts 1.0 GeV (energy) to kg (mass).
+ * System.out.println(Unit.valueOf("GeV").getConverterTo(KILOGRAM).convert(1.0));
+ * }
+ *
+ * > 1.7826617302520883E-27[/code]
+ */
+ public interface Model {
+
+ /**
+ * Holds the standard model (default).
+ */
+ public Model STANDARD = new Model() {
+
+ public Dimension getDimension(BaseUnit> unit) {
+ if (unit.equals(SI.METRE)) return Dimension.LENGTH;
+ if (unit.equals(SI.KILOGRAM)) return Dimension.MASS;
+ if (unit.equals(SI.KELVIN)) return Dimension.TEMPERATURE;
+ if (unit.equals(SI.SECOND)) return Dimension.TIME;
+ if (unit.equals(SI.AMPERE)) return Dimension.ELECTRIC_CURRENT;
+ if (unit.equals(SI.MOLE)) return Dimension.AMOUNT_OF_SUBSTANCE;
+ if (unit.equals(SI.CANDELA)) return SI.WATT.getDimension();
+ return new Dimension(new BaseUnit0.01
+ * (standard name %
).
+ */
+ public static final UnitdB
).
+ */
+ public static final Unitatom
).
+ */
+ public static final Unit0.3048 m
+ * (standard name ft
).
+ */
+ public static final Unit1200/3937 m
+ * (standard name foot_survey_us
).
+ * See also: foot
+ */
+ public static final Unit0.9144 m
+ * (standard name yd
).
+ */
+ public static final Unit0.0254 m
+ * (standard name in
).
+ */
+ public static final Unit1609.344 m
+ * (standard name mi
).
+ */
+ public static final Unit1852.0 m
+ * (standard name nmi
).
+ */
+ public static final Unit1E-10 m
+ * (standard name Å
).
+ */
+ public static final Unitua
).
+ */
+ public static final Unitly
).
+ */
+ public static final Unitpc
).
+ */
+ public static final Unit0.013837 {@link #INCH}
exactly
+ * (standard name pt
).
+ * @see #PIXEL
+ */
+ public static final Unit1/72 {@link #INCH}
+ * (standard name pixel
).
+ * It is the American point rounded to an even 1/72 inch.
+ * @see #POINT
+ */
+ public static final Unit60 s
+ * (standard name min
).
+ */
+ public static final Unit60 {@link #MINUTE}
+ * (standard name h
).
+ */
+ public static final Unit24 {@link #HOUR}
+ * (standard name d
).
+ */
+ public static final Unit7 {@link #DAY}
+ * (standard name week
).
+ */
+ public static final Unityear
).
+ */
+ public static final Unitmonth
).
+ */
+ public static final Unitday_sidereal
).
+ */
+ public static final Unityear_sidereal
).
+ */
+ public static final Unit365 {@link #DAY}
+ * (standard name year_calendar
).
+ */
+ public static final Unitu
).
+ */
+ public static final Unitme
).
+ */
+ public static final Unit453.59237 grams
(avoirdupois pound,
+ * standard name lb
).
+ */
+ public static final Unit1 / 16 {@link #POUND}
+ * (standard name oz
).
+ */
+ public static final Unit2000 {@link #POUND}
(short ton,
+ * standard name ton_us
).
+ */
+ public static final Unit2240 {@link #POUND}
(long ton,
+ * standard name ton_uk
).
+ */
+ public static final Unit1000 kg
(metric ton,
+ * standard name t
).
+ */
+ public static final Unite
).
+ */
+ public static final UnitFd
).
+ */
+ public static final UnitFr
).
+ */
+ public static final Unit5/9 °K
+ * (standard name °R
).
+ */
+ public static final Unit459.67 °R
(standard name °F
).
+ * @see #RANKINE
+ */
+ public static final Unit2π
+ * {@link SI#RADIAN}
(standard name rev
).
+ */
+ public static final Unit1/360 {@link #REVOLUTION}
+ * (standard name °
).
+ */
+ public static final Unit