DJUNITS - Delft Java UNIT System version 3.00  

Introduction

When a new Unit has been defined, it can be immediately used in a Scalar, Vector, or Matrix. Suppose we have defined a JerkUnit with [m/s3] as the SI unit. We can use it in a Double or Float Scalar, Vector, or Matrix:

DoubleScalar.Rel<JerkUnit> jerk1 =
    new DoubleScalar.Rel<>(1.2, JerkUnit.SI);
DoubleScalar.Rel<JerkUnit> jerk2 = jerk1.multiplyBy(2.0);
double[] sv = new double[] {1, 2, 3, 4, 5}; 
DoubleVector.Rel<JerkUnit> jerkVector = 
    new DoubleVector.Rel<JerkUnit>(sv, 
    JerkUnit.SI, StorageType.DENSE);

But it would be much nicer if we can define a Scalar called Jerk and a Vector called JerkVector that would allow us to code this as follows:

Jerk jerk1 = new Jerk(1.2, JerkUnit.SI);
Jerk jerk2 = jerk1.multiplyBy(2.0);
double[] sv = new double[] {1, 2, 3, 4, 5}; 
JerkVector jerkVector = 
    new JerkVector(sv, JerkUnit.SI, StorageType.DENSE);

The next sections will explain how to quickly build a new Relative Scalar type, and a new Scalar type that has an absolute and a relative subtype.

Extending a Relative ScalarType from the Abstract Scalar Template

A number of Abstract classes have been created that help to quickly instantiate new Scalar, Vector, and Matrix classes. For the Scalar class, these are AbstractDoubleScalarAbs and AbstractDoubleScalarRel. The AbstractDoubleScalarRel class takes two generic arguments: the unit, and the name of the class itself. The 2nd parameter might seem strange, as the definition looks to be self-referential. The way it is used is that in the methods of the Abstract class, the generics argument is used to indicate the return type and argument of methods that refer to the defined scalar type. So the first line of the new Jerk scalar is:

public class Jerk extends AbstractDoubleScalarRel<JerkUnit, Jerk>

The next lines define two constructors, one that takes a double argument, and one that takes another Jerk scalar:

public Jerk(final double value, final JerkUnit unit)
{
    super(value, unit);
}

public Jerk(final Jerk value)
{
    super(value);
}

Another method that has to be implemented is the instantiateTypeRel method. This method is used by the Abstract superclass to instantiate new scalar instances of the right type:

@Override
public final Jerk instantiateRel(final double value, final JerkUnit unit)
{
    return new Jerk(value, unit);
}

With these constructors, and the instantiate method, the new Scalar is ready to use.

Extra methods to implement

Often, extra methods are implemented for multiplication and division from the just defined type to other types. E.g., when we multiply the Jerk by a (Relative) Duration, we get an Acceleration. If we divide it by an Acceleration, we get a Frequency ([m/s3] / [m/s2] = [1/s]). These methods can be defined as follows:

public final Acceleration multiplyBy(final Duration v)
{
    return new Acceleration(this.si * v.si, AccelerationUnit.SI);
}

public final Frequency divideBy(final Acceleration v)
{
    return new Frequency(this.si / v.si, FrequencyUnit.SI);
}

We can make good use of the fact that the internal storage of all scalars is always in standard (if possible, SI) units.

Another methods that is often implemented is a static interpolate method, to interpolate between two Jerk scalars with a certain ratio (if the ration is less than zero, or greater than one, the same method can be used for linear extrapolation):

public static Jerk interpolate(final Jerk zero, 
    final Jerk one, final double ratio)
{
    return new Jerk(zero.getInUnit() * (1 - ratio) 
        + one.getInUnit(zero.getUnit()) * ratio, zero.getUnit());
}

The above interpolate method also shows how to get the result in the unit of the first argument. When the first argument has been defined in [ft/s3] and the second argument in [m/s3], the value of the second argument is first transformed into the [ft/s3] unit, before interpolating. The new unit is expressed in zero.getUnit(), so for the outside world, it will be visible in [ft/s3]. Note that the internal storage is always in the standard (SI) unit, so internally the value will still be stored in [m/s3].

Building a unit with absolute and relative subclasses

Most classes are just relative, and don't have an absolute version.