[wpiunits] Java units API rewrite (#6958)

Java generics are too limited to do what we need. This refactors generic code previously in Unit and Measure into unit-specific classes that can have unit-safe math operations (notably, times and divide) that can return values in known units instead of a wildcarded Measure<?>.

Unit-specific measure implementations are automatically generated by ./wpiunits/generate_units.py, which generates generic interfaces and mutable and immutable implementations of those interfaces. These make up the bulk of the diff of this PR (approximately 9300 LOC).

This also adds units for angular and linear velocities, accelerations, and momenta; moment of inertia; and torque.
This commit is contained in:
Sam Carlberg
2024-09-07 13:59:29 -04:00
committed by GitHub
parent 496e7c1bba
commit a9b885070e
178 changed files with 14750 additions and 2158 deletions

View File

@@ -0,0 +1,113 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
import edu.wpi.first.units.measure.Acceleration;
import edu.wpi.first.units.measure.ImmutableAcceleration;
import edu.wpi.first.units.measure.MutAcceleration;
/**
* A generic unit of acceleration.
*
* <p><strong>NOTE:</strong> This type is not compatible with unit-specific accelerations like
* {@link edu.wpi.first.units.measure.LinearAcceleration}. Authors of APIs that need to interact
* with all types should consider using a generic {@code Measure<? extends PerUnit<? extends
* PerUnit<[dimension>], TimeUnit>, TimeUnit>}. Bounded wildcards are necessary in order to
* interoperate with <i>any</i> subclass of the {@link edu.wpi.first.units.measure.Per} measurement
* type.
*
* @param <D> the unit of the accelerating quantity
*/
public final class AccelerationUnit<D extends Unit> extends PerUnit<VelocityUnit<D>, TimeUnit> {
@SuppressWarnings({"rawtypes", "unchecked"})
private static final CombinatoryUnitCache<VelocityUnit, TimeUnit, AccelerationUnit> cache =
new CombinatoryUnitCache<>(AccelerationUnit::new);
AccelerationUnit(VelocityUnit<D> velocity, TimeUnit period) {
super(
velocity.isBaseUnit() && period.isBaseUnit()
? null
: combine(velocity.getBaseUnit(), period.getBaseUnit()),
velocity,
period);
}
AccelerationUnit(
AccelerationUnit<D> baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
@Override
public Acceleration<D> of(double magnitude) {
return new ImmutableAcceleration<>(magnitude, toBaseUnits(magnitude), this);
}
@Override
public Acceleration<D> ofBaseUnits(double baseUnitMagnitude) {
return new ImmutableAcceleration<>(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public Acceleration<D> zero() {
return (Acceleration<D>) (Acceleration) super.zero();
}
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public Acceleration<D> one() {
return (Acceleration<D>) (Acceleration) super.one();
}
@Override
public MutAcceleration<D> mutable(double initialMagnitude) {
return new MutAcceleration<>(initialMagnitude, toBaseUnits(initialMagnitude), this);
}
@Override
public VelocityUnit<AccelerationUnit<D>> per(TimeUnit time) {
return VelocityUnit.combine(this, time);
}
/**
* Creates a ratio unit between this unit and an arbitrary other unit.
*
* @param other the other unit
* @param <U> the type of the other unit
* @return the ratio unit
*/
public <U extends Unit> PerUnit<AccelerationUnit<D>, U> per(U other) {
return PerUnit.combine(this, other);
}
/**
* Converts a measurement value in terms of another time unit to this unit.
*
* @param magnitude the magnitude of the measurement in terms of the other time unit
* @param otherUnit the other time unit
* @return the value of the measurement in terms of this unit
*/
public double convertFrom(double magnitude, AccelerationUnit<D> otherUnit) {
return fromBaseUnits(otherUnit.toBaseUnits(magnitude));
}
/**
* Combines a generic velocity and time period into a unit of acceleration.
*
* @param velocity the unit of velocity
* @param period the unit of the time period of acceleration
* @param <D> the unit of the accelerating quantity
* @return the combined acceleration unit
*/
@SuppressWarnings("unchecked")
public static <D extends Unit> AccelerationUnit<D> combine(
VelocityUnit<D> velocity, TimeUnit period) {
return cache.combine(velocity, period);
}
}

View File

@@ -1,32 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
/**
* Unit of angular dimension.
*
* <p>This is the base type for units of angular dimension. It is also used to specify the dimension
* for {@link Measure}: <code>Measure&lt;Angle&gt;</code>.
*
* <p>Actual units (such as {@link Units#Degrees} and {@link Units#Radians}) can be found in the
* {@link Units} class.
*/
// technically, angles are unitless dimensions
// eg Mass * Distance * Velocity<Angle> is equivalent to (Mass * Distance) / Time - otherwise known
// as Power - in other words, Velocity<Angle> is /actually/ Frequency
public class Angle extends Unit<Angle> {
Angle(Angle baseUnit, double baseUnitEquivalent, String name, String symbol) {
super(baseUnit, baseUnitEquivalent, name, symbol);
}
Angle(
Angle baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
}

View File

@@ -0,0 +1,93 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
import edu.wpi.first.units.measure.Angle;
import edu.wpi.first.units.measure.MutAngle;
/**
* Unit of angular dimension.
*
* <p>This is the base type for units of angular dimension. It is also used to specify the dimension
* for {@link Measure}: <code>Measure&lt;AngleUnit&gt;</code>.
*
* <p>Actual units (such as {@link Units#Degrees} and {@link Units#Radians}) can be found in the
* {@link Units} class.
*/
// technically, angles are unitless dimensions
// eg MassUnit * DistanceUnit * VelocityUnit<AngleUnit> is equivalent to (MassUnit * DistanceUnit) /
// TimeUnit - otherwise known
// as PowerUnit - in other words, VelocityUnit<AngleUnit> is /actually/ Frequency
public final class AngleUnit extends Unit {
AngleUnit(AngleUnit baseUnit, double baseUnitEquivalent, String name, String symbol) {
super(baseUnit, baseUnitEquivalent, name, symbol);
}
AngleUnit(
AngleUnit baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
@Override
public AngleUnit getBaseUnit() {
return (AngleUnit) super.getBaseUnit();
}
@Override
public Angle of(double magnitude) {
return Angle.ofRelativeUnits(magnitude, this);
}
@Override
public Angle ofBaseUnits(double baseUnitMagnitude) {
return Angle.ofBaseUnits(baseUnitMagnitude, this);
}
@Override
public MutAngle mutable(double initialMagnitude) {
return new MutAngle(initialMagnitude, toBaseUnits(initialMagnitude), this);
}
@Override
public AngularVelocityUnit per(TimeUnit period) {
return AngularVelocityUnit.combine(this, period);
}
/**
* Creates a ratio unit between this unit and an arbitrary other unit.
*
* @param other the other unit
* @param <U> the type of the other unit
* @return the ratio unit
*/
public <U extends Unit> PerUnit<AngleUnit, U> per(U other) {
return PerUnit.combine(this, other);
}
/**
* Converts a measurement value in terms of another angle unit to this unit.
*
* @param magnitude the magnitude of the measurement in terms of the other angle unit
* @param otherUnit the other angle unit
* @return the value of the measurement in terms of this unit
*/
public double convertFrom(double magnitude, AngleUnit otherUnit) {
return fromBaseUnits(otherUnit.toBaseUnits(magnitude));
}
@Override
public Angle zero() {
return (Angle) super.zero();
}
@Override
public Angle one() {
return (Angle) super.one();
}
}

View File

@@ -0,0 +1,102 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
import edu.wpi.first.units.measure.AngularAcceleration;
import edu.wpi.first.units.measure.ImmutableAngularAcceleration;
import edu.wpi.first.units.measure.MutAngularAcceleration;
/** A unit of angular acceleration, such as {@link Units#RadiansPerSecondPerSecond}. */
public final class AngularAccelerationUnit extends PerUnit<AngularVelocityUnit, TimeUnit> {
private static final CombinatoryUnitCache<AngularVelocityUnit, TimeUnit, AngularAccelerationUnit>
cache = new CombinatoryUnitCache<>(AngularAccelerationUnit::new);
AngularAccelerationUnit(AngularVelocityUnit velocity, TimeUnit period) {
super(
velocity.isBaseUnit() && period.isBaseUnit()
? null
: combine(velocity.getBaseUnit(), period.getBaseUnit()),
velocity,
period);
}
AngularAccelerationUnit(
AngularAccelerationUnit baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
/**
* Combines an angular velocity and time period unit into an angular acceleration.
*
* @param velocity the unit of velocity
* @param period the unit of time
* @return the combined angular acceleration unit
*/
public static AngularAccelerationUnit combine(AngularVelocityUnit velocity, TimeUnit period) {
return cache.combine(velocity, period);
}
@Override
public AngularAccelerationUnit getBaseUnit() {
return (AngularAccelerationUnit) super.getBaseUnit();
}
@Override
public AngularAcceleration of(double magnitude) {
return new ImmutableAngularAcceleration(magnitude, toBaseUnits(magnitude), this);
}
@Override
public AngularAcceleration ofBaseUnits(double baseUnitMagnitude) {
return new ImmutableAngularAcceleration(
fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public AngularAcceleration zero() {
return (AngularAcceleration) super.zero();
}
@Override
public AngularAcceleration one() {
return (AngularAcceleration) super.one();
}
@Override
public MutAngularAcceleration mutable(double initialMagnitude) {
return new MutAngularAcceleration(initialMagnitude, toBaseUnits(initialMagnitude), this);
}
@Override
public VelocityUnit<AngularAccelerationUnit> per(TimeUnit time) {
return VelocityUnit.combine(this, time);
}
/**
* Creates a ratio unit between this unit and an arbitrary other unit.
*
* @param other the other unit
* @param <U> the type of the other unit
* @return the ratio unit
*/
public <U extends Unit> PerUnit<AngularAccelerationUnit, U> per(U other) {
return PerUnit.combine(this, other);
}
/**
* Converts a measurement value in terms of another unit to this unit.
*
* @param magnitude the magnitude of the measurement in terms of the other unit
* @param otherUnit the other unit
* @return the value of the measurement in terms of this unit
*/
public double convertFrom(double magnitude, AngularAccelerationUnit otherUnit) {
return fromBaseUnits(otherUnit.toBaseUnits(magnitude));
}
}

View File

@@ -0,0 +1,114 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
import edu.wpi.first.units.measure.AngularMomentum;
import edu.wpi.first.units.measure.ImmutableAngularMomentum;
import edu.wpi.first.units.measure.MutAngularMomentum;
/**
* A unit of angular momentum, modeled as linear momentum of an object rotating some distance away
* from the axis of rotation.
*/
public final class AngularMomentumUnit extends MultUnit<LinearMomentumUnit, DistanceUnit> {
private static final CombinatoryUnitCache<LinearMomentumUnit, DistanceUnit, AngularMomentumUnit>
cache = new CombinatoryUnitCache<>(AngularMomentumUnit::new);
AngularMomentumUnit(LinearMomentumUnit momentumUnit, DistanceUnit distanceUnit) {
super(
momentumUnit.isBaseUnit() && distanceUnit.isBaseUnit()
? null
: combine(momentumUnit.getBaseUnit(), distanceUnit.getBaseUnit()),
momentumUnit,
distanceUnit);
}
AngularMomentumUnit(
AngularMomentumUnit baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
/**
* Combines a linear momentum and distance to create a unit of angular momentum.
*
* @param linear the linear momentum unit
* @param distance the unit of distance from the axis of rotation
* @return the combined angular momentum unit
*/
public static AngularMomentumUnit combine(LinearMomentumUnit linear, DistanceUnit distance) {
return cache.combine(linear, distance);
}
@Override
public AngularMomentumUnit getBaseUnit() {
return (AngularMomentumUnit) super.getBaseUnit();
}
@Override
public AngularMomentum of(double magnitude) {
return new ImmutableAngularMomentum(magnitude, toBaseUnits(magnitude), this);
}
@Override
public AngularMomentum ofBaseUnits(double baseUnitMagnitude) {
return new ImmutableAngularMomentum(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public AngularMomentum zero() {
return (AngularMomentum) super.zero();
}
@Override
public AngularMomentum one() {
return (AngularMomentum) super.one();
}
@Override
public MutAngularMomentum mutable(double magnitude) {
return new MutAngularMomentum(magnitude, toBaseUnits(magnitude), this);
}
@Override
public VelocityUnit<AngularMomentumUnit> per(TimeUnit time) {
return VelocityUnit.combine(this, time);
}
/**
* Creates a ratio unit between this unit and an arbitrary other unit.
*
* @param other the other unit
* @param <U> the type of the other unit
* @return the ratio unit
*/
public <U extends Unit> PerUnit<AngularMomentumUnit, U> per(U other) {
return PerUnit.combine(this, other);
}
/**
* Converts a measurement value in terms of another unit to this unit.
*
* @param magnitude the magnitude of the measurement in terms of the other unit
* @param otherUnit the other unit
* @return the value of the measurement in terms of this unit
*/
public double convertFrom(double magnitude, AngularMomentumUnit otherUnit) {
return fromBaseUnits(otherUnit.toBaseUnits(magnitude));
}
/**
* Multiplies this angular momentum by an angular velocity to yield a unit of moment of inertia.
*
* @param omega the unit of angular velocity
* @return the moment of inertia unit
*/
public MomentOfInertiaUnit mult(AngularVelocityUnit omega) {
return MomentOfInertiaUnit.combine(this, omega);
}
}

View File

@@ -0,0 +1,101 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
import edu.wpi.first.units.measure.AngularVelocity;
import edu.wpi.first.units.measure.ImmutableAngularVelocity;
import edu.wpi.first.units.measure.MutAngularVelocity;
/** A unit of angular velocity like {@link Units#RadiansPerSecond}. */
public final class AngularVelocityUnit extends PerUnit<AngleUnit, TimeUnit> {
private static final CombinatoryUnitCache<AngleUnit, TimeUnit, AngularVelocityUnit> cache =
new CombinatoryUnitCache<>(AngularVelocityUnit::new);
AngularVelocityUnit(AngleUnit numerator, TimeUnit denominator) {
super(
numerator.isBaseUnit() && denominator.isBaseUnit()
? null
: combine(numerator.getBaseUnit(), denominator.getBaseUnit()),
numerator,
denominator);
}
AngularVelocityUnit(
AngularVelocityUnit baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
/**
* Combines an angle unit and a period of time into a unit of angular velocity.
*
* @param angle the unit of the changing angle
* @param time the period of the changing angle
* @return the combined angular velocity unit
*/
public static AngularVelocityUnit combine(AngleUnit angle, TimeUnit time) {
return cache.combine(angle, time);
}
@Override
public AngularVelocityUnit getBaseUnit() {
return (AngularVelocityUnit) super.getBaseUnit();
}
@Override
public AngularVelocity of(double magnitude) {
return new ImmutableAngularVelocity(magnitude, toBaseUnits(magnitude), this);
}
@Override
public AngularVelocity ofBaseUnits(double baseUnitMagnitude) {
return new ImmutableAngularVelocity(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public AngularVelocity zero() {
return (AngularVelocity) super.zero();
}
@Override
public AngularVelocity one() {
return (AngularVelocity) super.one();
}
@Override
public MutAngularVelocity mutable(double initialMagnitude) {
return new MutAngularVelocity(initialMagnitude, toBaseUnits(initialMagnitude), this);
}
@Override
public AngularAccelerationUnit per(TimeUnit period) {
return AngularAccelerationUnit.combine(this, period);
}
/**
* Creates a ratio unit between this unit and an arbitrary other unit.
*
* @param other the other unit
* @param <U> the type of the other unit
* @return the ratio unit
*/
public <U extends Unit> PerUnit<AngularVelocityUnit, U> per(U other) {
return PerUnit.combine(this, other);
}
/**
* Converts a measurement value in terms of another unit to this unit.
*
* @param magnitude the magnitude of the measurement in terms of the other unit
* @param otherUnit the other unit
* @return the value of the measurement in terms of this unit
*/
public double convertFrom(double magnitude, AngularVelocityUnit otherUnit) {
return fromBaseUnits(otherUnit.toBaseUnits(magnitude));
}
}

View File

@@ -11,33 +11,30 @@ public final class BaseUnits {
}
/** The standard unit of distance, meters. */
public static final Distance Distance = new Distance(null, 1, "Meter", "m");
public static final DistanceUnit DistanceUnit = new DistanceUnit(null, 1, "Meter", "m");
/** The standard unit of time, seconds. */
public static final Time Time = new Time(null, 1, "Second", "s");
public static final TimeUnit TimeUnit = new TimeUnit(null, 1, "Second", "s");
/** The standard unit of mass, kilograms. */
public static final Mass Mass = new Mass(null, 1, "Kilogram", "Kg");
public static final MassUnit MassUnit = new MassUnit(null, 1, "Kilogram", "Kg");
/** The standard unit of angles, radians. */
public static final Angle Angle = new Angle(null, 1, "Radian", "rad");
public static final AngleUnit AngleUnit = new AngleUnit(null, 1, "Radian", "rad");
/** The standard "unitless" unit. */
public static final Dimensionless Value = new Dimensionless(null, 1, "<?>", "<?>");
public static final DimensionlessUnit Value = new DimensionlessUnit(null, 1, "<?>", "<?>");
/** The standard unit of voltage, volts. */
public static final Voltage Voltage = new Voltage(null, 1, "Volt", "V");
public static final VoltageUnit VoltageUnit = new VoltageUnit(null, 1, "Volt", "V");
/** The standard unit of electric current, amperes. */
public static final Current Current = new Current(null, 1, "Amp", "A");
public static final CurrentUnit CurrentUnit = new CurrentUnit(null, 1, "Amp", "A");
/** The standard unit of energy, joules. */
public static final Energy Energy = new Energy(null, 1, "Joule", "J");
/** The standard unit of power, watts. */
public static final Power Power = new Power(null, 1, "Watt", "W");
public static final EnergyUnit EnergyUnit = new EnergyUnit(null, 1, "Joule", "J");
/** The standard unit of temperature, kelvin. */
public static final Temperature Temperature =
new Temperature(null, x -> x, x -> x, "Kelvin", "K");
public static final TemperatureUnit TemperatureUnit =
new TemperatureUnit(null, x -> x, x -> x, "Kelvin", "K");
}

View File

@@ -0,0 +1,60 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
import edu.wpi.first.units.collections.LongToObjectHashMap;
import java.util.Objects;
import java.util.function.BiFunction;
/**
* A helper class for creating and caching combined unit objects. This helps to reduce unnecessary
* object allocation by reusing already-created units.
*
* @param <A> the type of the first unit to be combined
* @param <B> the type of the second unit to be combined
* @param <Out> the type of the combinatorial unit
*/
public final class CombinatoryUnitCache<A extends Unit, B extends Unit, Out extends Unit> {
/**
* Keep a cache of created instances so expressions like Volts.per(Meter) don't do any allocations
* after the first.
*/
private final LongToObjectHashMap<Out> m_cache = new LongToObjectHashMap<>();
private final BiFunction<? super A, ? super B, ? extends Out> m_constructor;
/**
* Creates a new combinatory unit cache. The cache is initially empty and is not shared across
* instances.
*
* @param constructor the constructor function to use to create new combined units
*/
public CombinatoryUnitCache(BiFunction<? super A, ? super B, ? extends Out> constructor) {
this.m_constructor =
Objects.requireNonNull(constructor, "Cache unit constructor must be provided");
}
/**
* Combines two units together and returns the result. The resulting units are cached and will be
* returned on successive calls to avoid allocating many duplicate objects. The combination output
* type is determined by the factory function passed into the cache's constructor.
*
* @param a the first unit
* @param b the second unit
* @return the combined unit
*/
public Out combine(A a, B b) {
final long key = ((long) a.hashCode()) << 32L | (b.hashCode() & 0xFFFFFFFFL);
var existing = m_cache.get(key);
if (existing != null) {
return existing;
}
var newUnit = m_constructor.apply(a, b);
m_cache.put(key, newUnit);
return newUnit;
}
}

View File

@@ -1,46 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
import static edu.wpi.first.units.Units.Watts;
/**
* Unit of electric current dimension.
*
* <p>This is the base type for units of current dimension. It is also used to specify the dimension
* for {@link Measure}: <code>Measure&lt;Current&gt;</code>.
*
* <p>Actual units (such as {@link Units#Amps} and {@link Units#Milliamps}) can be found in the
* {@link Units} class.
*/
public class Current extends Unit<Current> {
Current(Current baseUnit, double baseUnitEquivalent, String name, String symbol) {
super(baseUnit, baseUnitEquivalent, name, symbol);
}
Current(
Current baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
/**
* Constructs a unit of power equivalent to this unit of electrical current multiplied by another
* unit of voltage. For example, {@code Amps.times(Volts)} will return a unit of power equivalent
* to one Watt; {@code Amps.times(Millivolts)} will return a unit of power equivalent to a
* milliwatt, and so on.
*
* @param voltage the voltage unit to multiply by
* @param name the name of the resulting unit of power
* @param symbol the symbol used to represent the unit of power
* @return the power unit
*/
public Power times(Unit<Voltage> voltage, String name, String symbol) {
return new Power(Watts, this.toBaseUnits(1) * voltage.toBaseUnits(1), name, symbol);
}
}

View File

@@ -0,0 +1,105 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
import edu.wpi.first.units.measure.Current;
import edu.wpi.first.units.measure.ImmutableCurrent;
import edu.wpi.first.units.measure.MutCurrent;
/**
* Unit of electric current dimension.
*
* <p>This is the base type for units of current dimension. It is also used to specify the dimension
* for {@link Measure}: <code>Measure&lt;CurrentUnit&gt;</code>.
*
* <p>Actual units (such as {@link Units#Amps} and {@link Units#Milliamps}) can be found in the
* {@link Units} class.
*/
public final class CurrentUnit extends Unit {
CurrentUnit(CurrentUnit baseUnit, double baseUnitEquivalent, String name, String symbol) {
super(baseUnit, baseUnitEquivalent, name, symbol);
}
CurrentUnit(
CurrentUnit baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
@Override
public CurrentUnit getBaseUnit() {
return (CurrentUnit) super.getBaseUnit();
}
/**
* Constructs a unit of power equivalent to this unit of electrical current multiplied by another
* unit of voltage. For example, {@code Amps.times(Volts)} will return a unit of power equivalent
* to one Watt; {@code Amps.times(Millivolts)} will return a unit of power equivalent to a
* milliwatt, and so on.
*
* @param voltage the voltage unit to multiply by
* @param name the name of the resulting unit of power
* @param symbol the symbol used to represent the unit of power
* @return the power unit
*/
public PowerUnit mult(VoltageUnit voltage, String name, String symbol) {
return Units.derive(PowerUnit.combine(voltage, this)).named(name).symbol(symbol).make();
}
@Override
public Current of(double magnitude) {
return new ImmutableCurrent(magnitude, toBaseUnits(magnitude), this);
}
@Override
public Current ofBaseUnits(double baseUnitMagnitude) {
return new ImmutableCurrent(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public Current zero() {
return (Current) super.zero();
}
@Override
public Current one() {
return (Current) super.one();
}
@Override
public MutCurrent mutable(double initialMagnitude) {
return new MutCurrent(initialMagnitude, toBaseUnits(initialMagnitude), this);
}
@Override
public VelocityUnit<CurrentUnit> per(TimeUnit time) {
return VelocityUnit.combine(this, time);
}
/**
* Creates a ratio unit between this unit and an arbitrary other unit.
*
* @param other the other unit
* @param <U> the type of the other unit
* @return the ratio unit
*/
public <U extends Unit> PerUnit<CurrentUnit, U> per(U other) {
return PerUnit.combine(this, other);
}
/**
* Converts a measurement value in terms of another current unit to this unit.
*
* @param magnitude the magnitude of the measurement in terms of the other current unit
* @param otherUnit the other current unit
* @return the value of the measurement in terms of this unit
*/
public double convertFrom(double magnitude, CurrentUnit otherUnit) {
return fromBaseUnits(otherUnit.toBaseUnits(magnitude));
}
}

View File

@@ -1,30 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
/**
* A type of unit that corresponds to raw values and not any physical dimension, such as percentage.
*/
public class Dimensionless extends Unit<Dimensionless> {
/**
* Creates a new unit with the given name and multiplier to the base unit.
*
* @param baseUnitEquivalent the multiplier to convert this unit to the base unit of this type.
* @param name the name of the unit
* @param symbol the symbol of the unit
*/
Dimensionless(Dimensionless baseUnit, double baseUnitEquivalent, String name, String symbol) {
super(baseUnit, baseUnitEquivalent, name, symbol);
}
Dimensionless(
Dimensionless baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
}

View File

@@ -0,0 +1,99 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
import edu.wpi.first.units.measure.Dimensionless;
import edu.wpi.first.units.measure.ImmutableDimensionless;
import edu.wpi.first.units.measure.MutDimensionless;
/**
* A type of unit that corresponds to raw values and not any physical dimension, such as percentage.
*/
public final class DimensionlessUnit extends Unit {
/**
* Creates a new unit with the given name and multiplier to the base unit.
*
* @param baseUnitEquivalent the multiplier to convert this unit to the base unit of this type.
* @param name the name of the unit
* @param symbol the symbol of the unit
*/
DimensionlessUnit(
DimensionlessUnit baseUnit, double baseUnitEquivalent, String name, String symbol) {
super(baseUnit, baseUnitEquivalent, name, symbol);
}
DimensionlessUnit(
DimensionlessUnit baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
@Override
public DimensionlessUnit getBaseUnit() {
return (DimensionlessUnit) super.getBaseUnit();
}
@Override
public Dimensionless of(double magnitude) {
return new ImmutableDimensionless(magnitude, toBaseUnits(magnitude), this);
}
@Override
public Dimensionless ofBaseUnits(double baseUnitMagnitude) {
return new ImmutableDimensionless(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public Dimensionless zero() {
return (Dimensionless) super.zero();
}
@Override
public Dimensionless one() {
return (Dimensionless) super.one();
}
@Override
public MutDimensionless mutable(double initialMagnitude) {
return new MutDimensionless(initialMagnitude, toBaseUnits(initialMagnitude), this);
}
/**
* Converts a measurement value in terms of another dimensionless unit to this unit.
*
* @param magnitude the magnitude of the measurement in terms of the other dimensionless unit
* @param otherUnit the other dimensionless unit
* @return the value of the measurement in terms of this unit
*/
public double convertFrom(double magnitude, DimensionlessUnit otherUnit) {
return fromBaseUnits(otherUnit.toBaseUnits(magnitude));
}
/**
* Creates a frequency unit as the ratio of this dimensionless unit to the period of time in which
* a single cycle is made.
*
* @param period the cycle period
* @return the combined frequency unit
*/
@Override
public FrequencyUnit per(TimeUnit period) {
return FrequencyUnit.combine(this, period);
}
/**
* Creates a ratio unit between this unit and an arbitrary other unit.
*
* @param other the other unit
* @param <U> the type of the other unit
* @return the ratio unit
*/
public <U extends Unit> PerUnit<DimensionlessUnit, U> per(U other) {
return PerUnit.combine(this, other);
}
}

View File

@@ -1,29 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
/**
* Unit of linear dimension.
*
* <p>This is the base type for units of linear dimension. It is also used to specify the dimension
* for {@link Measure}: <code>Measure&lt;Distance&gt;</code>.
*
* <p>Actual units (such as {@link Units#Meters} and {@link Units#Inches}) can be found in the
* {@link Units} class.
*/
public class Distance extends Unit<Distance> {
Distance(Distance baseUnit, double baseUnitEquivalent, String name, String symbol) {
super(baseUnit, baseUnitEquivalent, name, symbol);
}
Distance(
Distance baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
}

View File

@@ -0,0 +1,102 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
import edu.wpi.first.units.measure.Distance;
import edu.wpi.first.units.measure.ImmutableDistance;
import edu.wpi.first.units.measure.MutDistance;
/**
* Unit of linear dimension.
*
* <p>This is the base type for units of linear dimension. It is also used to specify the dimension
* for {@link Measure}: <code>Measure&lt;DistanceUnit&gt;</code>.
*
* <p>Actual units (such as {@link Units#Meters} and {@link Units#Inches}) can be found in the
* {@link Units} class.
*/
public final class DistanceUnit extends Unit {
DistanceUnit(DistanceUnit baseUnit, double baseUnitEquivalent, String name, String symbol) {
super(baseUnit, baseUnitEquivalent, name, symbol);
}
DistanceUnit(
DistanceUnit baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
@Override
public DistanceUnit getBaseUnit() {
return (DistanceUnit) super.getBaseUnit();
}
@Override
public LinearVelocityUnit per(TimeUnit period) {
return LinearVelocityUnit.combine(this, period);
}
/**
* Creates a ratio unit between this unit and an arbitrary other unit.
*
* @param other the other unit
* @param <U> the type of the other unit
* @return the ratio unit
*/
public <U extends Unit> PerUnit<DistanceUnit, U> per(U other) {
return PerUnit.combine(this, other);
}
/**
* Converts a measurement value in terms of another distance unit to this unit.
*
* @param magnitude the magnitude of the measurement in terms of the other distance unit
* @param otherUnit the other distance unit
* @return the value of the measurement in terms of this unit
*/
public double convertFrom(double magnitude, DistanceUnit otherUnit) {
return fromBaseUnits(otherUnit.toBaseUnits(magnitude));
}
@Override
public Distance of(double magnitude) {
return new ImmutableDistance(magnitude, toBaseUnits(magnitude), this);
}
@Override
public Distance ofBaseUnits(double baseUnitMagnitude) {
return new ImmutableDistance(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public Distance zero() {
return (Distance) super.zero();
}
@Override
public Distance one() {
return (Distance) super.one();
}
@Override
public MutDistance mutable(double initialMagnitude) {
return new MutDistance(initialMagnitude, toBaseUnits(initialMagnitude), this);
}
/**
* Multiplies this distance unit by a unit of force to create a unit of torque.
*
* @param force the unit of force
* @return the combined torque unit
*/
public TorqueUnit multAsTorque(ForceUnit force) {
return TorqueUnit.combine(this, force);
}
// TODO: Add a multAsEnergy equivalent
}

View File

@@ -1,29 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
/**
* Unit of energy dimension.
*
* <p>This is the base type for units of energy dimension. It is also used to specify the dimension
* for {@link Measure}: <code>Measure&lt;Energy&gt;</code>.
*
* <p>Actual units (such as {@link Units#Joules} and {@link Units#Kilojoules}) can be found in the
* {@link Units} class.
*/
public class Energy extends Unit<Energy> {
Energy(
Energy baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
Energy(Energy baseUnit, double baseUnitEquivalent, String name, String symbol) {
super(baseUnit, baseUnitEquivalent, name, symbol);
}
}

View File

@@ -0,0 +1,96 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
import edu.wpi.first.units.measure.Energy;
import edu.wpi.first.units.measure.ImmutableEnergy;
import edu.wpi.first.units.measure.MutEnergy;
/**
* Unit of energy dimension.
*
* <p>This is the base type for units of energy dimension. It is also used to specify the dimension
* for {@link Measure}: <code>Measure&lt;EnergyUnit&gt;</code>.
*
* <p>Actual units (such as {@link Units#Joules} and {@link Units#Kilojoules}) can be found in the
* {@link Units} class.
*/
public final class EnergyUnit extends Unit {
EnergyUnit(
EnergyUnit baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
EnergyUnit(EnergyUnit baseUnit, double baseUnitEquivalent, String name, String symbol) {
super(baseUnit, baseUnitEquivalent, name, symbol);
}
@Override
public EnergyUnit getBaseUnit() {
return (EnergyUnit) super.getBaseUnit();
}
/**
* Combines this unit of energy with a unit of time to create a unit of power.
*
* @param period the period of the change in energy
* @return the combined unit of power
*/
@Override
public PowerUnit per(TimeUnit period) {
return PowerUnit.combine(this, period);
}
/**
* Creates a ratio unit between this unit and an arbitrary other unit.
*
* @param other the other unit
* @param <U> the type of the other unit
* @return the ratio unit
*/
public <U extends Unit> PerUnit<EnergyUnit, U> per(U other) {
return PerUnit.combine(this, other);
}
/**
* Converts a measurement value in terms of another unit to this unit.
*
* @param magnitude the magnitude of the measurement in terms of the other unit
* @param otherUnit the other unit
* @return the value of the measurement in terms of this unit
*/
public double convertFrom(double magnitude, EnergyUnit otherUnit) {
return fromBaseUnits(otherUnit.toBaseUnits(magnitude));
}
@Override
public Energy of(double magnitude) {
return new ImmutableEnergy(magnitude, toBaseUnits(magnitude), this);
}
@Override
public Energy ofBaseUnits(double baseUnitMagnitude) {
return new ImmutableEnergy(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public Energy zero() {
return (Energy) super.zero();
}
@Override
public Energy one() {
return (Energy) super.one();
}
@Override
public MutEnergy mutable(double initialMagnitude) {
return new MutEnergy(initialMagnitude, toBaseUnits(initialMagnitude), this);
}
}

View File

@@ -0,0 +1,113 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
import edu.wpi.first.units.measure.Force;
import edu.wpi.first.units.measure.ImmutableForce;
import edu.wpi.first.units.measure.MutForce;
/** A unit of force like {@link Units#Newtons}. */
public final class ForceUnit extends MultUnit<MassUnit, LinearAccelerationUnit> {
private static final CombinatoryUnitCache<MassUnit, LinearAccelerationUnit, ForceUnit> cache =
new CombinatoryUnitCache<>(ForceUnit::new);
ForceUnit(MassUnit mass, LinearAccelerationUnit acceleration) {
super(
mass.isBaseUnit() && acceleration.isBaseUnit()
? null
: combine(mass.getBaseUnit(), acceleration.getBaseUnit()),
mass,
acceleration);
}
ForceUnit(
ForceUnit baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
/**
* Combines a mass and (linear) acceleration to form a unit of force.
*
* @param mass the unit of mass
* @param acceleration the unit of acceleration
* @return the combined unit of force
*/
public static ForceUnit combine(MassUnit mass, LinearAccelerationUnit acceleration) {
return cache.combine(mass, acceleration);
}
@Override
public ForceUnit getBaseUnit() {
return (ForceUnit) super.getBaseUnit();
}
/**
* Multiplies this force unit by a unit of distance to create a unit of torque.
*
* @param distance the unit of distance
* @return the combined torque unit
*/
public TorqueUnit multAsTorque(DistanceUnit distance) {
return TorqueUnit.combine(distance, this);
}
// TODO: Add a multAsEnergy equivalent
@Override
public Force of(double magnitude) {
return new ImmutableForce(magnitude, toBaseUnits(magnitude), this);
}
@Override
public Force ofBaseUnits(double baseUnitMagnitude) {
return new ImmutableForce(toBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public Force zero() {
return (Force) super.zero();
}
@Override
public Force one() {
return (Force) super.one();
}
@Override
public MutForce mutable(double initialMagnitude) {
return new MutForce(initialMagnitude, toBaseUnits(initialMagnitude), this);
}
@Override
public VelocityUnit<ForceUnit> per(TimeUnit time) {
return VelocityUnit.combine(this, time);
}
/**
* Creates a ratio unit between this unit and an arbitrary other unit.
*
* @param other the other unit
* @param <U> the type of the other unit
* @return the ratio unit
*/
public <U extends Unit> PerUnit<ForceUnit, U> per(U other) {
return PerUnit.combine(this, other);
}
/**
* Converts a measurement value in terms of another unit to this unit.
*
* @param magnitude the magnitude of the measurement in terms of the other unit
* @param otherUnit the other unit
* @return the value of the measurement in terms of this unit
*/
public double convertFrom(double magnitude, ForceUnit otherUnit) {
return fromBaseUnits(otherUnit.toBaseUnits(magnitude));
}
}

View File

@@ -0,0 +1,114 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
import static edu.wpi.first.units.Units.Value;
import edu.wpi.first.units.measure.Frequency;
import edu.wpi.first.units.measure.ImmutableFrequency;
import edu.wpi.first.units.measure.MutFrequency;
/** A unit of frequency like {@link edu.wpi.first.units.Units#Hertz}. */
public final class FrequencyUnit extends PerUnit<DimensionlessUnit, TimeUnit> {
private static final CombinatoryUnitCache<DimensionlessUnit, TimeUnit, FrequencyUnit> cache =
new CombinatoryUnitCache<>(FrequencyUnit::new);
FrequencyUnit(DimensionlessUnit numerator, TimeUnit denominator) {
super(
numerator.isBaseUnit() && denominator.isBaseUnit()
? null
: combine(numerator.getBaseUnit(), denominator.getBaseUnit()),
numerator,
denominator);
}
FrequencyUnit(
FrequencyUnit baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
/**
* Combines a dimensionless unit and a cycle period to create a frequency.
*
* @param dim the dimensionless unit
* @param period the unit of time
* @return the combined unit of frequency
*/
public static FrequencyUnit combine(DimensionlessUnit dim, TimeUnit period) {
return cache.combine(dim, period);
}
@Override
public FrequencyUnit getBaseUnit() {
return (FrequencyUnit) super.getBaseUnit();
}
/**
* Inverts a unit of time to get its corresponding frequency (as if the unit of time is the period
* of the frequency).
*
* @param time period of the associated frequency
* @return the frequency associated with the period
*/
public static FrequencyUnit inverse(TimeUnit time) {
return combine(Value, time);
}
@Override
public Frequency of(double magnitude) {
return new ImmutableFrequency(magnitude, toBaseUnits(magnitude), this);
}
@Override
public Frequency ofBaseUnits(double baseUnitMagnitude) {
return new ImmutableFrequency(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public Frequency zero() {
return (Frequency) super.zero();
}
@Override
public Frequency one() {
return (Frequency) super.one();
}
@Override
public MutFrequency mutable(double initialMagnitude) {
return new MutFrequency(initialMagnitude, toBaseUnits(initialMagnitude), this);
}
@Override
public VelocityUnit<FrequencyUnit> per(TimeUnit time) {
return VelocityUnit.combine(this, time);
}
/**
* Creates a ratio unit between this unit and an arbitrary other unit.
*
* @param other the other unit
* @param <U> the type of the other unit
* @return the ratio unit
*/
public <U extends Unit> PerUnit<FrequencyUnit, U> per(U other) {
return PerUnit.combine(this, other);
}
/**
* Converts a measurement value in terms of another unit to this unit.
*
* @param magnitude the magnitude of the measurement in terms of the other unit
* @param otherUnit the other unit
* @return the value of the measurement in terms of this unit
*/
public double convertFrom(double magnitude, FrequencyUnit otherUnit) {
return fromBaseUnits(otherUnit.toBaseUnits(magnitude));
}
}

View File

@@ -4,7 +4,8 @@
package edu.wpi.first.units;
import java.util.Objects;
import edu.wpi.first.units.measure.Dimensionless;
import edu.wpi.first.units.mutable.GenericMutableMeasureImpl;
/**
* A measure holds the magnitude and unit of some dimension, such as distance, time, or speed. An
@@ -12,28 +13,13 @@ import java.util.Objects;
* situations and gives compile-time safety. Two measures with the same <i>unit</i> and
* <i>magnitude</i> are effectively equivalent objects.
*
* @param magnitude the magnitude of the measure in terms of its unit
* @param baseUnitMagnitude the magnitude of the measure in terms of its base unit
* @param unit the unit of the measurement
* @param <U> the unit type of the measure
*/
public class ImmutableMeasure<U extends Unit<U>> implements Measure<U> {
private final double m_magnitude;
private final double m_baseUnitMagnitude;
private final U m_unit;
/**
* Creates a new immutable measure instance. This shouldn't be used directly; prefer one of the
* factory methods instead.
*
* @param magnitude the magnitude of this measure
* @param unit the unit of this measure.
*/
@SuppressWarnings("unchecked")
ImmutableMeasure(double magnitude, double baseUnitMagnitude, Unit<U> unit) {
Objects.requireNonNull(unit, "Unit cannot be null");
m_magnitude = magnitude;
m_baseUnitMagnitude = baseUnitMagnitude;
m_unit = (U) unit;
}
public record ImmutableMeasure<U extends Unit>(double magnitude, double baseUnitMagnitude, U unit)
implements Measure<U> {
/**
* Creates a new measure in the given unit with a magnitude equal to the given one in base units.
*
@@ -42,8 +28,7 @@ public class ImmutableMeasure<U extends Unit<U>> implements Measure<U> {
* @param unit the unit of measure
* @return a new measure
*/
public static <U extends Unit<U>> ImmutableMeasure<U> ofBaseUnits(
double baseUnitMagnitude, Unit<U> unit) {
public static <U extends Unit> ImmutableMeasure<U> ofBaseUnits(double baseUnitMagnitude, U unit) {
return new ImmutableMeasure<>(unit.fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, unit);
}
@@ -55,51 +40,53 @@ public class ImmutableMeasure<U extends Unit<U>> implements Measure<U> {
* @param unit the unit of measure
* @return a new measure
*/
public static <U extends Unit<U>> ImmutableMeasure<U> ofRelativeUnits(
double relativeMagnitude, Unit<U> unit) {
public static <U extends Unit> ImmutableMeasure<U> ofRelativeUnits(
double relativeMagnitude, U unit) {
return new ImmutableMeasure<>(relativeMagnitude, unit.toBaseUnits(relativeMagnitude), unit);
}
/** Gets the unitless magnitude of this measure. */
@Override
public double magnitude() {
return m_magnitude;
}
@Override
public double baseUnitMagnitude() {
return m_baseUnitMagnitude;
}
/** Gets the units of this measure. */
@Override
public U unit() {
return m_unit;
}
/**
* Checks for <i>object equality</i>. To check if two measures are <i>equivalent</i>, use {@link
* #isEquivalent(Measure) isEquivalent}.
*/
@Override
public boolean equals(Object o) {
return o instanceof Measure<?> that
&& Objects.equals(m_unit, that.unit())
&& m_baseUnitMagnitude == that.baseUnitMagnitude();
}
@Override
public int hashCode() {
return Objects.hash(m_magnitude, m_unit);
}
@Override
public Measure<U> copy() {
return this; // already immutable, no need to allocate a new object
}
@Override
public String toString() {
return toShortString();
public MutableMeasure<U, ?, ?> mutableCopy() {
return new GenericMutableMeasureImpl<>(magnitude, baseUnitMagnitude, unit);
}
@Override
public Measure<U> unaryMinus() {
return ofBaseUnits(0 - baseUnitMagnitude, unit);
}
@Override
public Measure<U> plus(Measure<? extends U> other) {
return ofBaseUnits(baseUnitMagnitude + other.baseUnitMagnitude(), unit);
}
@Override
public Measure<U> minus(Measure<? extends U> other) {
return ofBaseUnits(baseUnitMagnitude - other.baseUnitMagnitude(), unit);
}
@Override
public Measure<U> times(double multiplier) {
return ofBaseUnits(baseUnitMagnitude * multiplier, unit);
}
@Override
public Measure<U> times(Dimensionless multiplier) {
return ofBaseUnits(baseUnitMagnitude * multiplier.baseUnitMagnitude(), unit);
}
@Override
public Measure<U> divide(double divisor) {
return ofBaseUnits(baseUnitMagnitude / divisor, unit);
}
@Override
public Measure<U> divide(Dimensionless divisor) {
return ofBaseUnits(baseUnitMagnitude / divisor.baseUnitMagnitude(), unit);
}
}

View File

@@ -0,0 +1,125 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
import edu.wpi.first.units.measure.ImmutableLinearAcceleration;
import edu.wpi.first.units.measure.LinearAcceleration;
import edu.wpi.first.units.measure.MutLinearAcceleration;
/**
* A unit of linear acceleration like {@link edu.wpi.first.units.Units#MetersPerSecondPerSecond}.
*/
public final class LinearAccelerationUnit extends PerUnit<LinearVelocityUnit, TimeUnit> {
private static final CombinatoryUnitCache<LinearVelocityUnit, TimeUnit, LinearAccelerationUnit>
cache = new CombinatoryUnitCache<>(LinearAccelerationUnit::new);
LinearAccelerationUnit(LinearVelocityUnit numerator, TimeUnit denominator) {
super(
numerator.isBaseUnit() && denominator.isBaseUnit()
? null
: combine(numerator.getBaseUnit(), denominator.getBaseUnit()),
numerator,
denominator);
}
LinearAccelerationUnit(
LinearAccelerationUnit baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
/**
* Combines a linear velocity and time unit to form a unit of linear acceleration.
*
* @param velocity the unit of linear velocity
* @param period the unit of time
* @return the combined unit of linear acceleration
*/
public static LinearAccelerationUnit combine(LinearVelocityUnit velocity, TimeUnit period) {
return cache.combine(velocity, period);
}
@Override
public LinearAccelerationUnit getBaseUnit() {
return (LinearAccelerationUnit) super.getBaseUnit();
}
@Override
public LinearAcceleration of(double magnitude) {
return new ImmutableLinearAcceleration(magnitude, toBaseUnits(magnitude), this);
}
@Override
public LinearAcceleration ofBaseUnits(double baseUnitMagnitude) {
return new ImmutableLinearAcceleration(
fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public LinearAcceleration zero() {
return (LinearAcceleration) super.zero();
}
@Override
public LinearAcceleration one() {
return (LinearAcceleration) super.one();
}
@Override
public MutLinearAcceleration mutable(double initialMagnitude) {
return new MutLinearAcceleration(initialMagnitude, toBaseUnits(initialMagnitude), this);
}
@Override
public VelocityUnit<LinearAccelerationUnit> per(TimeUnit time) {
return VelocityUnit.combine(this, time);
}
/**
* Creates a ratio unit between this unit and an arbitrary other unit.
*
* @param other the other unit
* @param <U> the type of the other unit
* @return the ratio unit
*/
public <U extends Unit> PerUnit<LinearAccelerationUnit, U> per(U other) {
return PerUnit.combine(this, other);
}
/**
* Converts a measurement value in terms of another unit to this unit.
*
* @param magnitude the magnitude of the measurement in terms of the other unit
* @param otherUnit the other unit
* @return the value of the measurement in terms of this unit
*/
public double convertFrom(double magnitude, LinearAccelerationUnit otherUnit) {
return fromBaseUnits(otherUnit.toBaseUnits(magnitude));
}
/**
* Gets the unit of the changing velocity. This is equivalent to {@link #numerator()} and is left
* for historical purposes.
*
* @return the unit of the changing velocity
*/
public LinearVelocityUnit getUnit() {
return numerator();
}
/**
* Gets the unit of the acceleration period (how long it takes for a measured velocity to change
* by one unit of velocity). This is equivalent to {@link #numerator()} and is left for historical
* purposes.
*
* @return the unit of the acceleration period
*/
public TimeUnit getPeriod() {
return denominator();
}
}

View File

@@ -0,0 +1,111 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
import edu.wpi.first.units.measure.ImmutableLinearMomentum;
import edu.wpi.first.units.measure.LinearMomentum;
import edu.wpi.first.units.measure.MutLinearMomentum;
/** A unit of linear momentum like {@link edu.wpi.first.units.Units#KilogramMetersPerSecond}. */
public final class LinearMomentumUnit extends MultUnit<MassUnit, LinearVelocityUnit> {
private static final CombinatoryUnitCache<MassUnit, LinearVelocityUnit, LinearMomentumUnit>
cache = new CombinatoryUnitCache<>(LinearMomentumUnit::new);
LinearMomentumUnit(MassUnit unit, LinearVelocityUnit linearVelocityUnit) {
super(
unit.isBaseUnit() && linearVelocityUnit.isBaseUnit()
? null
: combine(unit.getBaseUnit(), linearVelocityUnit.getBaseUnit()),
unit,
linearVelocityUnit);
}
LinearMomentumUnit(
MultUnit<MassUnit, LinearVelocityUnit> baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
/**
* Combines a mass and linear velocity unit to form a combined linear momentum unit.
*
* @param mass the unit of mass
* @param velocity the unit of velocity
* @return the combined unit of momentum
*/
public static LinearMomentumUnit combine(MassUnit mass, LinearVelocityUnit velocity) {
return cache.combine(mass, velocity);
}
@Override
public LinearMomentumUnit getBaseUnit() {
return (LinearMomentumUnit) super.getBaseUnit();
}
@Override
public LinearMomentum of(double magnitude) {
return new ImmutableLinearMomentum(magnitude, toBaseUnits(magnitude), this);
}
@Override
public LinearMomentum ofBaseUnits(double baseUnitMagnitude) {
return new ImmutableLinearMomentum(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public LinearMomentum zero() {
return (LinearMomentum) super.zero();
}
@Override
public LinearMomentum one() {
return (LinearMomentum) super.one();
}
@Override
public MutLinearMomentum mutable(double initialMagnitude) {
return new MutLinearMomentum(initialMagnitude, toBaseUnits(initialMagnitude), this);
}
@Override
public VelocityUnit<LinearMomentumUnit> per(TimeUnit time) {
return VelocityUnit.combine(this, time);
}
/**
* Creates a ratio unit between this unit and an arbitrary other unit.
*
* @param other the other unit
* @param <U> the type of the other unit
* @return the ratio unit
*/
public <U extends Unit> PerUnit<LinearMomentumUnit, U> per(U other) {
return PerUnit.combine(this, other);
}
/**
* Converts a measurement value in terms of another unit to this unit.
*
* @param magnitude the magnitude of the measurement in terms of the other unit
* @param otherUnit the other unit
* @return the value of the measurement in terms of this unit
*/
public double convertFrom(double magnitude, LinearMomentumUnit otherUnit) {
return fromBaseUnits(otherUnit.toBaseUnits(magnitude));
}
/**
* Multiplies this unit by distance to form a unit of angular momentum.
*
* @param distance the unit of distance
* @return the combined unit of angular momentum
*/
public AngularMomentumUnit mult(DistanceUnit distance) {
return AngularMomentumUnit.combine(this, distance);
}
}

View File

@@ -0,0 +1,107 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
import edu.wpi.first.units.measure.ImmutableLinearVelocity;
import edu.wpi.first.units.measure.LinearVelocity;
import edu.wpi.first.units.measure.MutLinearVelocity;
/** A unit of linear velocity like {@link edu.wpi.first.units.Units#MetersPerSecond}. */
public final class LinearVelocityUnit extends PerUnit<DistanceUnit, TimeUnit> {
private static final CombinatoryUnitCache<DistanceUnit, TimeUnit, LinearVelocityUnit> cache =
new CombinatoryUnitCache<>(LinearVelocityUnit::new);
LinearVelocityUnit(DistanceUnit unit, TimeUnit period) {
super(
unit.isBaseUnit() && period.isBaseUnit()
? null
: combine(unit.getBaseUnit(), period.getBaseUnit()),
unit,
period);
}
LinearVelocityUnit(
PerUnit<DistanceUnit, TimeUnit> baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
/**
* Combines a distance and time unit for form a combined unit of velocity.
*
* @param distance the unit of distance
* @param period the unit of time
* @return the combined velocity unit
*/
public static LinearVelocityUnit combine(DistanceUnit distance, TimeUnit period) {
return cache.combine(distance, period);
}
@Override
public LinearVelocityUnit getBaseUnit() {
return (LinearVelocityUnit) super.getBaseUnit();
}
@Override
public LinearVelocity of(double magnitude) {
return new ImmutableLinearVelocity(magnitude, toBaseUnits(magnitude), this);
}
@Override
public LinearVelocity ofBaseUnits(double baseUnitMagnitude) {
return new ImmutableLinearVelocity(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public LinearVelocity zero() {
return (LinearVelocity) super.zero();
}
@Override
public LinearVelocity one() {
return (LinearVelocity) super.one();
}
@Override
public MutLinearVelocity mutable(double value) {
return new MutLinearVelocity(value, toBaseUnits(value), this);
}
/**
* Combines this velocity with a time period of change to form a unit of acceleration.
*
* @param period the period of change in the velocity
* @return the combined acceleration unit
*/
@Override
public LinearAccelerationUnit per(TimeUnit period) {
return LinearAccelerationUnit.combine(this, period);
}
/**
* Creates a ratio unit between this unit and an arbitrary other unit.
*
* @param other the other unit
* @param <U> the type of the other unit
* @return the ratio unit
*/
public <U extends Unit> PerUnit<LinearVelocityUnit, U> per(U other) {
return PerUnit.combine(this, other);
}
/**
* Converts a measurement value in terms of another unit to this unit.
*
* @param magnitude the magnitude of the measurement in terms of the other unit
* @param otherUnit the other unit
* @return the value of the measurement in terms of this unit
*/
public double convertFrom(double magnitude, LinearVelocityUnit otherUnit) {
return fromBaseUnits(otherUnit.toBaseUnits(magnitude));
}
}

View File

@@ -1,30 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
/**
* Unit of mass dimension.
*
* <p>This is the base type for units of mass dimension. It is also used to specify the dimension
* for {@link Measure}: <code>Measure&lt;Mass&gt;</code>.
*
* <p>Actual units (such as {@link Units#Grams} and {@link Units#Pounds}) can be found in the {@link
* Units} class.
*/
public class Mass extends Unit<Mass> {
/** Creates a new unit with the given name and multiplier to the base unit. */
Mass(Mass baseUnit, double baseUnitEquivalent, String name, String symbol) {
super(baseUnit, baseUnitEquivalent, name, symbol);
}
Mass(
Mass baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
}

View File

@@ -0,0 +1,112 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
import edu.wpi.first.units.measure.ImmutableMass;
import edu.wpi.first.units.measure.Mass;
import edu.wpi.first.units.measure.MutMass;
/**
* Unit of mass dimension.
*
* <p>This is the base type for units of mass dimension. It is also used to specify the dimension
* for the mass-specific {@link Mass} measurement type.
*
* <p>Actual units (such as {@link Units#Grams} and {@link Units#Pounds}) can be found in the {@link
* Units} class.
*/
public final class MassUnit extends Unit {
/** Creates a new unit with the given name and multiplier to the base unit. */
MassUnit(MassUnit baseUnit, double baseUnitEquivalent, String name, String symbol) {
super(baseUnit, baseUnitEquivalent, name, symbol);
}
MassUnit(
MassUnit baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
@Override
public MassUnit getBaseUnit() {
return (MassUnit) super.getBaseUnit();
}
@Override
public Mass of(double magnitude) {
return new ImmutableMass(magnitude, toBaseUnits(magnitude), this);
}
@Override
public Mass ofBaseUnits(double baseUnitMagnitude) {
return new ImmutableMass(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public Mass zero() {
return (Mass) super.zero();
}
@Override
public Mass one() {
return (Mass) super.one();
}
@Override
public MutMass mutable(double initialMagnitude) {
return new MutMass(initialMagnitude, toBaseUnits(initialMagnitude), this);
}
@Override
public VelocityUnit<MassUnit> per(TimeUnit period) {
return VelocityUnit.combine(this, period);
}
/**
* Creates a ratio unit between this unit and an arbitrary other unit.
*
* @param other the other unit
* @param <U> the type of the other unit
* @return the ratio unit
*/
public <U extends Unit> PerUnit<MassUnit, U> per(U other) {
return PerUnit.combine(this, other);
}
/**
* Converts a measurement value in terms of another mass unit to this unit.
*
* @param magnitude the magnitude of the measurement in terms of the other mass unit
* @param otherUnit the other mass unit
* @return the value of the measurement in terms of this unit
*/
public double convertFrom(double magnitude, MassUnit otherUnit) {
return fromBaseUnits(otherUnit.toBaseUnits(magnitude));
}
/**
* Multiplies this mass unit by a unit of linear velocity to form a combined unit of linear
* momentum.
*
* @param velocity the unit of velocity
* @return the combined unit of momentum
*/
public LinearMomentumUnit mult(LinearVelocityUnit velocity) {
return LinearMomentumUnit.combine(this, velocity);
}
/**
* Multiplies this mass unit by a unit of linear acceleration to form a combined unit of force.
*
* @param acceleration the unit of acceleration
* @return the combined unit of force
*/
public ForceUnit mult(LinearAccelerationUnit acceleration) {
return ForceUnit.combine(this, acceleration);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,107 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
import edu.wpi.first.units.measure.ImmutableMomentOfInertia;
import edu.wpi.first.units.measure.MomentOfInertia;
import edu.wpi.first.units.measure.MutMomentOfInertia;
/**
* A unit of moment of inertia, like {@link edu.wpi.first.units.Units#KilogramSquareMeters}. Moments
* of inertia describe how much an object resists being rotated, analogous to mass's resistance to
* being accelerated along a line.
*/
public final class MomentOfInertiaUnit extends PerUnit<AngularMomentumUnit, AngularVelocityUnit> {
private static final CombinatoryUnitCache<
AngularMomentumUnit, AngularVelocityUnit, MomentOfInertiaUnit>
cache = new CombinatoryUnitCache<>(MomentOfInertiaUnit::new);
MomentOfInertiaUnit(AngularMomentumUnit numerator, AngularVelocityUnit denominator) {
super(
numerator.isBaseUnit() && denominator.isBaseUnit()
? null
: combine(numerator.getBaseUnit(), denominator.getBaseUnit()),
numerator,
denominator);
}
MomentOfInertiaUnit(
PerUnit<AngularMomentumUnit, AngularVelocityUnit> baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
/**
* Combines an angular momentum and angular velocity unit to form a moment of inertia unit.
*
* @param momentumUnit the unit of angular momentum
* @param velocityUnit the unit of angular velocity
* @return the combined moment of inertia unit
*/
public static MomentOfInertiaUnit combine(
AngularMomentumUnit momentumUnit, AngularVelocityUnit velocityUnit) {
return cache.combine(momentumUnit, velocityUnit);
}
@Override
public MomentOfInertiaUnit getBaseUnit() {
return (MomentOfInertiaUnit) super.getBaseUnit();
}
@Override
public MomentOfInertia of(double magnitude) {
return new ImmutableMomentOfInertia(magnitude, toBaseUnits(magnitude), this);
}
@Override
public MomentOfInertia ofBaseUnits(double baseUnitMagnitude) {
return new ImmutableMomentOfInertia(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public MomentOfInertia zero() {
return (MomentOfInertia) super.zero();
}
@Override
public MomentOfInertia one() {
return (MomentOfInertia) super.one();
}
@Override
public MutMomentOfInertia mutable(double initialMagnitude) {
return new MutMomentOfInertia(initialMagnitude, toBaseUnits(initialMagnitude), this);
}
@Override
public VelocityUnit<MomentOfInertiaUnit> per(TimeUnit time) {
return VelocityUnit.combine(this, time);
}
/**
* Creates a ratio unit between this unit and an arbitrary other unit.
*
* @param other the other unit
* @param <U> the type of the other unit
* @return the ratio unit
*/
public <U extends Unit> PerUnit<MomentOfInertiaUnit, U> per(U other) {
return PerUnit.combine(this, other);
}
/**
* Converts a measurement value in terms of another unit to this unit.
*
* @param magnitude the magnitude of the measurement in terms of the other unit
* @param otherUnit the other unit
* @return the value of the measurement in terms of this unit
*/
public double convertFrom(double magnitude, MomentOfInertiaUnit otherUnit) {
return fromBaseUnits(otherUnit.toBaseUnits(magnitude));
}
}

View File

@@ -1,123 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
import edu.wpi.first.units.collections.LongToObjectHashMap;
import java.util.Objects;
/**
* A combinatory unit type that is equivalent to the product of two other others. Note that
* algebraic reduction is not possible in Java's generic type system, so {@code Mult<A, B>} is not
* type-compatible with {@code Mult<B, A>}!
*
* @param <A> the type of the first unit in the result
* @param <B> the type of the second unit in the result
*/
public class Mult<A extends Unit<A>, B extends Unit<B>> extends Unit<Mult<A, B>> {
private final A m_unitA;
private final B m_unitB;
@SuppressWarnings("rawtypes")
private static final LongToObjectHashMap<Mult> cache = new LongToObjectHashMap<>();
/**
* Creates a new product unit. Consider using {@link #combine} instead of manually calling this
* constructor.
*
* @param a the first unit of the product
* @param b the second unit of the product
*/
protected Mult(A a, B b) {
super(
a.isBaseUnit() && b.isBaseUnit() ? null : combine(a.getBaseUnit(), b.getBaseUnit()),
a.toBaseUnits(1) * b.toBaseUnits(1),
a.name() + "-" + b.name(),
a.symbol() + "*" + b.symbol());
m_unitA = a;
m_unitB = b;
}
Mult(
Mult<A, B> baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
m_unitA = baseUnit.unitA();
m_unitB = baseUnit.unitB();
}
/**
* Creates a new Mult unit derived from two arbitrary units multiplied together.
*
* <pre>
* Mult.combine(Volts, Meters) // Volt-Meters
* </pre>
*
* <p>It's recommended to use the convenience function {@link Unit#mult(Unit)} instead of calling
* this factory directly.
*
* @param <A> the type of the first unit
* @param <B> the type of the second unit
* @param a the first unit
* @param b the second unit
* @return the combined unit
*/
@SuppressWarnings("unchecked")
public static <A extends Unit<A>, B extends Unit<B>> Mult<A, B> combine(A a, B b) {
final long key = ((long) a.hashCode()) << 32L | (b.hashCode() & 0xFFFFFFFFL);
if (cache.containsKey(key)) {
return cache.get(key);
}
var mult = new Mult<A, B>(a, b);
cache.put(key, mult);
return mult;
}
/**
* Gets the first unit of the product.
*
* @return the first unit
*/
public A unitA() {
return m_unitA;
}
/**
* Gets the second unit of the product.
*
* @return the second unit
*/
public B unitB() {
return m_unitB;
}
@Override
public String toString() {
return "(" + m_unitA.toString() + " * " + m_unitB.toString() + ")";
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!super.equals(o)) {
return false;
}
Mult<?, ?> mult = (Mult<?, ?>) o;
return Objects.equals(m_unitA, mult.m_unitA) && Objects.equals(m_unitB, mult.m_unitB);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), m_unitA, m_unitB);
}
}

View File

@@ -0,0 +1,229 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
import edu.wpi.first.units.measure.ImmutableMult;
import edu.wpi.first.units.measure.Mult;
import edu.wpi.first.units.measure.MutMult;
import java.util.Objects;
/**
* A combinatory unit type that is equivalent to the product of two other others. Note that
* algebraic reduction is not possible in Java's generic type system, so {@code MultUnit<A, B>} is
* not type-compatible with {@code MultUnit<B, A>}!
*
* @param <A> the type of the first unit in the result
* @param <B> the type of the second unit in the result
*/
public class MultUnit<A extends Unit, B extends Unit> extends Unit {
private final A m_unitA;
private final B m_unitB;
@SuppressWarnings("rawtypes")
private static final CombinatoryUnitCache<Unit, Unit, MultUnit> cache =
new CombinatoryUnitCache<>(MultUnit::new);
/**
* Creates a new product unit. Consider using {@link #combine} instead of manually calling this
* constructor.
*
* @param a the first unit of the product
* @param b the second unit of the product
*/
private MultUnit(A a, B b) {
super(
a.isBaseUnit() && b.isBaseUnit() ? null : combine(a.getBaseUnit(), b.getBaseUnit()),
a.toBaseUnits(1) * b.toBaseUnits(1),
a.name() + "-" + b.name(),
a.symbol() + "*" + b.symbol());
m_unitA = a;
m_unitB = b;
}
/**
* Creates a new product unit. Subclasses of {@code MultUnit} should use this constructor.
*
* @param baseUnit the base unit. Set this to null if the unit being constructed is its own base
* unit
* @param a the first unit of the product
* @param b the second unit of the product
*/
protected MultUnit(MultUnit<A, B> baseUnit, A a, B b) {
super(
baseUnit,
a.toBaseUnits(1) * b.toBaseUnits(1),
a.name() + "-" + b.name(),
a.symbol() + "*" + b.symbol());
m_unitA = a;
m_unitB = b;
}
MultUnit(
MultUnit<A, B> baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
m_unitA = getBaseUnit().unitA();
m_unitB = getBaseUnit().unitB();
}
/**
* Creates a new MultUnit unit derived from two arbitrary units multiplied together.
*
* <pre>
* MultUnit.combine(Volts, Meters) // Volt-Meters
* </pre>
*
* @param <A> the type of the first unit
* @param <B> the type of the second unit
* @param a the first unit
* @param b the second unit
* @return the combined unit
*/
@SuppressWarnings("unchecked")
public static <A extends Unit, B extends Unit> MultUnit<A, B> combine(A a, B b) {
return cache.combine(a, b);
}
/**
* {@inheritDoc}
*
* <p>Note: When called on an object of type {@code MultUnit} (and <i>not</i> a subclass!), this
* method will always return a {@link edu.wpi.first.units.measure.Mult} instance. If you want to
* avoid casting, use {@link #ofNativeBaseUnits(double)} that returns a {@code Per} instance
* directly.
*
* @param magnitude the magnitude of the measure in terms of its base units.
* @return the measurement object
*/
@Override
public Measure<? extends MultUnit<A, B>> of(double magnitude) {
return ofNative(magnitude);
}
/**
* {@inheritDoc}
*
* <p>Note: When called on an object of type {@code MultUnit} (and <i>not</i> a subclass!), this
* method will always return a {@link edu.wpi.first.units.measure.Mult} instance. If you want to
* avoid casting, use {@link #ofNativeBaseUnits(double)} that returns a {@code Per} instance
* directly.
*
* @param baseUnitMagnitude the magnitude of the measure in terms of its base units.
* @return the measurement object
*/
@Override
public Measure<? extends MultUnit<A, B>> ofBaseUnits(double baseUnitMagnitude) {
return ofNativeBaseUnits(baseUnitMagnitude);
}
/**
* Creates a new immutable measurement of the given magnitude in terms of this unit. This will
* always return a {@code Mult} object and cannot be overridden by subclasses.
*
* @param magnitude the magnitude of the measurement.
* @return the measurement object
* @see #of(double)
*/
public final Mult<A, B> ofNative(double magnitude) {
return new ImmutableMult<>(magnitude, toBaseUnits(magnitude), this);
}
/**
* Creates a new immutable measurement of the given magnitude in terms of the unit's base unit.
* This will always return a {@code Mult} object and cannot be overridden by subclasses.
*
* @param baseUnitMagnitude the magnitude of the measure in terms of its base units.
* @return the measurement object
* @see #ofBaseUnits(double)
*/
public final Mult<A, B> ofNativeBaseUnits(double baseUnitMagnitude) {
return new ImmutableMult<>(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
@SuppressWarnings("unchecked")
public Measure<? extends MultUnit<A, B>> zero() {
return (Measure<? extends MultUnit<A, B>>) super.zero();
}
@Override
@SuppressWarnings("unchecked")
public Measure<? extends MultUnit<A, B>> one() {
return (Measure<? extends MultUnit<A, B>>) super.one();
}
@Override
public MutableMeasure<? extends MultUnit<A, B>, ?, ?> mutable(double initialMagnitude) {
return new MutMult<>(initialMagnitude, toBaseUnits(initialMagnitude), this);
}
@Override
public Unit per(TimeUnit time) {
return VelocityUnit.combine(this, time);
}
/**
* Converts a measurement value in terms of another unit to this unit.
*
* @param magnitude the magnitude of the measurement in terms of the other unit
* @param otherUnit the other unit
* @return the value of the measurement in terms of this unit
*/
public double convertFrom(double magnitude, MultUnit<A, B> otherUnit) {
return fromBaseUnits(otherUnit.toBaseUnits(magnitude));
}
@Override
@SuppressWarnings("unchecked")
public MultUnit<A, B> getBaseUnit() {
return (MultUnit<A, B>) super.getBaseUnit();
}
/**
* Gets the first unit of the product.
*
* @return the first unit
*/
public A unitA() {
return m_unitA;
}
/**
* Gets the second unit of the product.
*
* @return the second unit
*/
public B unitB() {
return m_unitB;
}
@Override
public String toString() {
return "(" + m_unitA.toString() + " * " + m_unitB.toString() + ")";
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!super.equals(o)) {
return false;
}
MultUnit<?, ?> multUnit = (MultUnit<?, ?>) o;
return Objects.equals(m_unitA, multUnit.m_unitA) && Objects.equals(m_unitB, multUnit.m_unitB);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), m_unitA, m_unitB);
}
}

View File

@@ -4,111 +4,54 @@
package edu.wpi.first.units;
import java.util.Objects;
import edu.wpi.first.units.measure.Dimensionless;
/**
* A specialization of {@link Measure} that allows for mutability. This is intended to be used for
* memory use reasons (such as on the memory-restricted roboRIO 1 or 2 or SBC coprocessors) and
* should NOT be exposed in the public API for a class that uses it.
* A mutable measurement can be used to keep a single object allocation and reference whose state is
* mutated or changed as it is used. This is helpful for optimizing memory usage to keep garbage
* collection time - and its associated loop overruns - to a minimum.
*
* <p>The advantage of using this class is to reuse one instance of a measurement object, as opposed
* to instantiating a new immutable instance every time an operation is performed. This will reduce
* memory pressure, but comes at the cost of increased code complexity and sensitivity to race
* conditions if misused.
*
* <p>Any unsafe methods are prefixed with {@code mut_*}, such as {@link #mut_plus(Measure)} or
* {@link #mut_replace(Measure)}. These methods will change the internal state of the measurement
* object, and as such can be dangerous to use. They are primarily intended for use to track
* internal state of things like sensors
*
* @param <U> the type of the unit of measure
* @param <U> The dimension of measurement.
* @param <Base> The base measure type.
* @param <MutSelf> The self type. This MUST inherit from the base measure type.
*/
public final class MutableMeasure<U extends Unit<U>> implements Measure<U> {
private double m_magnitude;
private double m_baseUnitMagnitude;
private U m_unit;
private MutableMeasure(double initialMagnitude, double baseUnitMagnitude, U unit) {
m_magnitude = initialMagnitude;
m_baseUnitMagnitude = baseUnitMagnitude;
m_unit = unit;
}
public interface MutableMeasure<
U extends Unit, Base extends Measure<U>, MutSelf extends MutableMeasure<U, Base, MutSelf>>
extends Measure<U> {
/**
* Overwrites the state of this measure with new values.
*
* @param magnitude the new magnitude in terms of the new unit
* @param newUnit the new unit
* @return this measure
*/
MutSelf mut_replace(double magnitude, U newUnit);
/**
* Creates a new mutable measure that is a copy of the given one.
* Overwrites the state of this measure and replaces it completely with values from the given one.
* The magnitude, base unit magnitude, and unit will all be copied. This is functionally the same
* as calling {@code other.mutableCopy()}, but copying to a pre-existing mutable measure instead
* of instantiating a new one.
*
* @param <U> the type of the units of measure
* @param measure the measure to create a mutable copy of
* @return a new mutable measure with an initial state equal to the given measure
* @param other the other measure to copy values from
* @return this measure
*/
public static <U extends Unit<U>> MutableMeasure<U> mutable(Measure<U> measure) {
return new MutableMeasure<>(measure.magnitude(), measure.baseUnitMagnitude(), measure.unit());
}
/**
* Creates a new mutable measure with a magnitude of 0 in the given unit.
*
* @param <U> the type of the units of measure
* @param unit the unit of measure
* @return a new mutable measure
*/
public static <U extends Unit<U>> MutableMeasure<U> zero(U unit) {
return mutable(unit.zero());
}
/**
* Creates a new mutable measure in the given unit with a magnitude equal to the given one in base
* units.
*
* @param <U> the type of the units of measure
* @param baseUnitMagnitude the magnitude of the measure, in terms of the base unit of measure
* @param unit the unit of measure
* @return a new mutable measure
*/
public static <U extends Unit<U>> MutableMeasure<U> ofBaseUnits(
double baseUnitMagnitude, U unit) {
return new MutableMeasure<>(unit.fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, unit);
}
/**
* Creates a new mutable measure in the given unit with a magnitude in terms of that unit.
*
* @param <U> the type of the units of measure
* @param relativeMagnitude the magnitude of the measure
* @param unit the unit of measure
* @return a new mutable measure
*/
public static <U extends Unit<U>> MutableMeasure<U> ofRelativeUnits(
double relativeMagnitude, U unit) {
return new MutableMeasure<>(relativeMagnitude, unit.toBaseUnits(relativeMagnitude), unit);
default MutSelf mut_replace(Base other) {
return mut_replace(other.magnitude(), other.unit());
}
@Override
public double magnitude() {
return m_magnitude;
}
@Override
public double baseUnitMagnitude() {
return m_baseUnitMagnitude;
}
@Override
public U unit() {
return m_unit;
}
// UNSAFE
Base copy();
/**
* Sets the new magnitude of the measurement. The magnitude must be in terms of the {@link
* #unit()}.
*
* @param magnitude the new magnitude of the measurement
* @return this mutable measure
*/
public void mut_setMagnitude(double magnitude) {
m_magnitude = magnitude;
m_baseUnitMagnitude = m_unit.toBaseUnits(magnitude);
default MutSelf mut_setMagnitude(double magnitude) {
return mut_replace(magnitude, unit());
}
/**
@@ -116,37 +59,10 @@ public final class MutableMeasure<U extends Unit<U>> implements Measure<U> {
* the current unit.
*
* @param baseUnitMagnitude the new magnitude of the measurement
* @return this mutable measure
*/
public void mut_setBaseUnitMagnitude(double baseUnitMagnitude) {
m_baseUnitMagnitude = baseUnitMagnitude;
m_magnitude = m_unit.fromBaseUnits(baseUnitMagnitude);
}
/**
* Overwrites the state of this measure and replaces it with values from the given one.
*
* @param other the other measure to copy values from
* @return this measure
*/
public MutableMeasure<U> mut_replace(Measure<U> other) {
m_magnitude = other.magnitude();
m_baseUnitMagnitude = other.baseUnitMagnitude();
m_unit = other.unit();
return this;
}
/**
* Overwrites the state of this measure with new values.
*
* @param magnitude the new magnitude in terms of the new unit
* @param unit the new unit
* @return this measure
*/
public MutableMeasure<U> mut_replace(double magnitude, U unit) {
this.m_magnitude = magnitude;
this.m_baseUnitMagnitude = unit.toBaseUnits(magnitude);
this.m_unit = unit;
return this;
default MutSelf mut_setBaseUnitMagnitude(double baseUnitMagnitude) {
return mut_replace(unit().fromBaseUnits(baseUnitMagnitude), unit());
}
/**
@@ -156,29 +72,20 @@ public final class MutableMeasure<U extends Unit<U>> implements Measure<U> {
* @param raw the raw value to accumulate by
* @return the measure
*/
public MutableMeasure<U> mut_acc(double raw) {
this.m_magnitude += raw;
this.m_baseUnitMagnitude += m_unit.toBaseUnits(raw);
return this;
default MutSelf mut_acc(double raw) {
return mut_setBaseUnitMagnitude(magnitude() + raw);
}
/**
* Increments the current magnitude of the measure by the amount of the given measure.
*
* @param other the measure whose value should be added to this one
* @return the measure
* @return this measure
*/
public MutableMeasure<U> mut_acc(Measure<U> other) {
m_baseUnitMagnitude += other.baseUnitMagnitude();
// can't naively use m_magnitude += other.in(m_unit) because the units may not
// be scalar multiples (eg adding 0C to 100K should result in 373.15K, not 100K)
m_magnitude = m_unit.fromBaseUnits(m_baseUnitMagnitude);
return this;
default MutSelf mut_acc(Base other) {
return mut_setMagnitude(magnitude() + unit().fromBaseUnits(other.baseUnitMagnitude()));
}
// Math
/**
* Adds another measurement to this one. This will mutate the object instead of generating a new
* measurement object.
@@ -186,8 +93,8 @@ public final class MutableMeasure<U extends Unit<U>> implements Measure<U> {
* @param other the measurement to add
* @return this measure
*/
public MutableMeasure<U> mut_plus(Measure<U> other) {
return mut_plus(other.magnitude(), other.unit());
default MutSelf mut_plus(Base other) {
return mut_acc(other);
}
/**
@@ -196,36 +103,35 @@ public final class MutableMeasure<U extends Unit<U>> implements Measure<U> {
* having to wrap raw numbers in a {@code Measure} object and pay for an object allocation.
*
* @param magnitude the magnitude of the other measurement.
* @param unit the unit of the other measurement
* @param otherUnit the unit of the other measurement
* @return this measure
*/
public MutableMeasure<U> mut_plus(double magnitude, U unit) {
mut_setBaseUnitMagnitude(m_baseUnitMagnitude + unit.toBaseUnits(magnitude));
return this;
default MutSelf mut_plus(double magnitude, U otherUnit) {
return mut_setBaseUnitMagnitude(magnitude() + otherUnit.toBaseUnits(magnitude));
}
/**
* Subtracts another measurement to this one. This will mutate the object instead of generating a
* new measurement object.
*
* @param other the measurement to add
* @param other the measurement to subtract from this one
* @return this measure
*/
public MutableMeasure<U> mut_minus(Measure<U> other) {
return mut_minus(other.magnitude(), other.unit());
default MutSelf mut_minus(Base other) {
return mut_setBaseUnitMagnitude(baseUnitMagnitude() - other.baseUnitMagnitude());
}
/**
* Subtracts another measurement to this one. This will mutate the object instead of generating a
* new measurement object. This is a denormalized version of {@link #mut_minus(Measure)} to avoid
* having to wrap raw numbers in a {@code Measure} object and pay for an object allocation.
* Subtracts another measurement from this one. This will mutate the object instead of generating
* a new measurement object. This is a denormalized version of {@link #mut_minus(Measure)} to
* avoid having to wrap raw numbers in a {@code Measure} object and pay for an object allocation.
*
* @param magnitude the magnitude of the other measurement.
* @param unit the unit of the other measurement
* @param otherUnit the unit of the other measurement
* @return this measure
*/
public MutableMeasure<U> mut_minus(double magnitude, U unit) {
return mut_plus(-magnitude, unit);
default MutSelf mut_minus(double magnitude, U otherUnit) {
return mut_setBaseUnitMagnitude(baseUnitMagnitude() - otherUnit.toBaseUnits(magnitude));
}
/**
@@ -235,9 +141,8 @@ public final class MutableMeasure<U extends Unit<U>> implements Measure<U> {
* @param multiplier the multiplier to scale the measurement by
* @return this measure
*/
public MutableMeasure<U> mut_times(double multiplier) {
mut_setBaseUnitMagnitude(m_baseUnitMagnitude * multiplier);
return this;
default MutSelf mut_times(double multiplier) {
return mut_setBaseUnitMagnitude(baseUnitMagnitude() * multiplier);
}
/**
@@ -247,7 +152,7 @@ public final class MutableMeasure<U extends Unit<U>> implements Measure<U> {
* @param multiplier the multiplier to scale the measurement by
* @return this measure
*/
public MutableMeasure<U> mut_times(Measure<? extends Dimensionless> multiplier) {
default MutSelf mut_times(Dimensionless multiplier) {
return mut_times(multiplier.baseUnitMagnitude());
}
@@ -258,9 +163,8 @@ public final class MutableMeasure<U extends Unit<U>> implements Measure<U> {
* @param divisor the divisor to scale the measurement by
* @return this measure
*/
public MutableMeasure<U> mut_divide(double divisor) {
mut_setBaseUnitMagnitude(m_baseUnitMagnitude / divisor);
return this;
default MutSelf mut_divide(double divisor) {
return mut_times(1 / divisor);
}
/**
@@ -270,29 +174,7 @@ public final class MutableMeasure<U extends Unit<U>> implements Measure<U> {
* @param divisor the divisor to scale the measurement by
* @return this measure
*/
public MutableMeasure<U> mut_divide(Measure<? extends Dimensionless> divisor) {
default MutSelf mut_divide(Dimensionless divisor) {
return mut_divide(divisor.baseUnitMagnitude());
}
@Override
public Measure<U> copy() {
return new ImmutableMeasure<>(m_magnitude, m_baseUnitMagnitude, m_unit);
}
@Override
public String toString() {
return toShortString();
}
@Override
public boolean equals(Object o) {
return o instanceof Measure<?> that
&& Objects.equals(m_unit, that.unit())
&& this.isEquivalent(that);
}
@Override
public int hashCode() {
return Objects.hash(m_magnitude, m_unit);
}
}

View File

@@ -1,140 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
import edu.wpi.first.units.collections.LongToObjectHashMap;
import java.util.Objects;
/**
* Generic combinatory unit type that represents the proportion of one unit to another, such as
* Meters per Second or Radians per Celsius.
*
* <p>Note: {@link Velocity} is used to represent the velocity dimension, rather than {@code
* Per<Distance, Time>}.
*
* @param <N> the type of the numerator unit
* @param <D> the type of the denominator unit
*/
public class Per<N extends Unit<N>, D extends Unit<D>> extends Unit<Per<N, D>> {
private final N m_numerator;
private final D m_denominator;
/**
* Keep a cache of created instances so expressions like Volts.per(Meter) don't do any allocations
* after the first.
*/
@SuppressWarnings("rawtypes")
private static final LongToObjectHashMap<Per> cache = new LongToObjectHashMap<>();
/**
* Creates a new proportional unit derived from the ratio of one unit to another. Consider using
* {@link #combine} instead of manually calling this constructor.
*
* @param numerator the numerator unit
* @param denominator the denominator unit
*/
protected Per(N numerator, D denominator) {
super(
numerator.isBaseUnit() && denominator.isBaseUnit()
? null
: combine(numerator.getBaseUnit(), denominator.getBaseUnit()),
numerator.toBaseUnits(1) / denominator.toBaseUnits(1),
numerator.name() + " per " + denominator.name(),
numerator.symbol() + "/" + denominator.symbol());
m_numerator = numerator;
m_denominator = denominator;
}
Per(
Per<N, D> baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
m_numerator = baseUnit.numerator();
m_denominator = baseUnit.denominator();
}
/**
* Creates a new Per unit derived from an arbitrary numerator and time denominator units. Using a
* denominator with a unit of time is discouraged; use {@link Velocity} instead.
*
* <pre>
* Per.combine(Volts, Meters) // possible PID constant
* </pre>
*
* <p>It's recommended to use the convenience function {@link Unit#per(Unit)} instead of calling
* this factory directly.
*
* @param <N> the type of the numerator unit
* @param <D> the type of the denominator unit
* @param numerator the numerator unit
* @param denominator the denominator for unit time
* @return the combined unit
*/
@SuppressWarnings("unchecked")
public static <N extends Unit<N>, D extends Unit<D>> Per<N, D> combine(
N numerator, D denominator) {
final long key = ((long) numerator.hashCode()) << 32L | (denominator.hashCode() & 0xFFFFFFFFL);
var existing = cache.get(key);
if (existing != null) {
return existing;
}
var newUnit = new Per<>(numerator, denominator);
cache.put(key, newUnit);
return newUnit;
}
/**
* Gets the numerator unit. For a {@code Per<A, B>}, this will return the {@code A} unit.
*
* @return the numerator unit
*/
public N numerator() {
return m_numerator;
}
/**
* Gets the denominator unit. For a {@code Per<A, B>}, this will return the {@code B} unit.
*
* @return the denominator unit
*/
public D denominator() {
return m_denominator;
}
/**
* Returns the reciprocal of this Per.
*
* @return the reciprocal
*/
public Per<D, N> reciprocal() {
return m_denominator.per(m_numerator);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!super.equals(o)) {
return false;
}
Per<?, ?> per = (Per<?, ?>) o;
return Objects.equals(m_numerator, per.m_numerator)
&& Objects.equals(m_denominator, per.m_denominator);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), m_numerator, m_denominator);
}
}

View File

@@ -0,0 +1,287 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
import edu.wpi.first.units.measure.ImmutablePer;
import edu.wpi.first.units.measure.MutPer;
import edu.wpi.first.units.measure.Per;
import java.util.Objects;
/**
* Generic combinatory unit type that represents the proportion of one unit to another, such as
* Meters per Second or Radians per Celsius.
*
* @param <N> the type of the numerator unit
* @param <D> the type of the denominator unit
*/
public class PerUnit<N extends Unit, D extends Unit> extends Unit {
private final N m_numerator;
private final D m_denominator;
/**
* Keep a cache of created instances so expressions like Volts.per(Meter) don't do any allocations
* after the first.
*/
@SuppressWarnings("rawtypes")
private static final CombinatoryUnitCache<Unit, Unit, PerUnit> cache =
new CombinatoryUnitCache<>(PerUnit::new);
/**
* Creates a new proportional unit derived from the ratio of one unit to another. Consider using
* {@link #combine} instead of manually calling this constructor.
*
* @param numerator the numerator unit
* @param denominator the denominator unit
*/
private PerUnit(N numerator, D denominator) {
super(
numerator.isBaseUnit() && denominator.isBaseUnit()
? null
: combine(numerator.getBaseUnit(), denominator.getBaseUnit()),
numerator.toBaseUnits(1) / denominator.toBaseUnits(1),
numerator.name() + " per " + denominator.name(),
numerator.symbol() + "/" + denominator.symbol());
m_numerator = numerator;
m_denominator = denominator;
}
/**
* Creates a new proportional unit derived from the ratio of one unit to another. Subclasses of
* {@code PerUnit} should use this constructor.
*
* @param baseUnit the base unit. Set this to null if the unit being constructed is its own base
* unit
* @param numerator the numerator unit
* @param denominator the denominator unit
*/
protected PerUnit(PerUnit<N, D> baseUnit, N numerator, D denominator) {
super(
baseUnit,
numerator.toBaseUnits(1) / denominator.toBaseUnits(1),
numerator.name() + " per " + denominator.name(),
numerator.symbol() + "/" + denominator.symbol());
m_numerator = numerator;
m_denominator = denominator;
}
/** {@inheritDoc} */
PerUnit(
PerUnit<N, D> baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
m_numerator = getBaseUnit().numerator();
m_denominator = getBaseUnit().denominator();
}
/**
* Creates a new PerUnit unit derived from an arbitrary numerator and time denominator units.
*
* <pre>
* PerUnit.combine(Volts, Meters) // possible PID constant
* </pre>
*
* @param <N> the type of the numerator unit
* @param <D> the type of the denominator unit
* @param numerator the numerator unit
* @param denominator the denominator for unit time
* @return the combined unit
*/
@SuppressWarnings("unchecked")
public static <N extends Unit, D extends Unit> PerUnit<N, D> combine(N numerator, D denominator) {
return cache.combine(numerator, denominator);
}
@Override
@SuppressWarnings("unchecked")
public PerUnit<N, D> getBaseUnit() {
return (PerUnit<N, D>) super.getBaseUnit();
}
/**
* Gets the numerator unit. For a {@code PerUnit<A, B>}, this will return the {@code A} unit.
*
* @return the numerator unit
*/
public N numerator() {
return m_numerator;
}
/**
* Gets the denominator unit. For a {@code PerUnit<A, B>}, this will return the {@code B} unit.
*
* @return the denominator unit
*/
public D denominator() {
return m_denominator;
}
/**
* Returns the reciprocal of this PerUnit.
*
* @return the reciprocal
*/
@SuppressWarnings("unchecked")
public PerUnit<D, N> reciprocal() {
if (m_numerator instanceof TimeUnit t) {
// Dividing by time, return a velocity
return (PerUnit<D, N>) VelocityUnit.combine(m_denominator, t);
} else {
// Generic case
return combine(m_denominator, m_numerator);
}
}
/**
* Multiplies this unit by a unit of its denominator.
*
* @param denom the denominator-typed unit to multiply by
* @return the result
*/
public N mult(D denom) {
if (denom.equivalent(denominator())) {
return numerator();
}
return Units.derive(numerator())
.toBase(denom.getConverterToBase().div(denominator().getConverterToBase()))
.fromBase(denom.getConverterFromBase().div(denominator().getConverterFromBase()))
.named(name() + " " + denom.name())
.symbol(symbol() + "-" + denom.symbol())
.make();
}
/**
* {@inheritDoc}
*
* <p>Note: When called on an object of type {@code PerUnit} (and <i>not</i> a subclass!), this
* method will always return a {@link edu.wpi.first.units.measure.Per} instance. If you want to
* avoid casting, use {@link #ofNative(double)} that returns a {@code Per} instance directly.
*
* @param magnitude the magnitude of the measure
* @return the ratio measure
*/
@Override
public Measure<? extends PerUnit<N, D>> of(double magnitude) {
return ofNative(magnitude);
}
/**
* {@inheritDoc}
*
* <p>Note: When called on an object of type {@code PerUnit} (and <i>not</i> a subclass!), this
* method will always return a {@link edu.wpi.first.units.measure.Per} instance. If you want to
* avoid casting, use {@link #ofNativeBaseUnits(double)} that returns a {@code Per} instance
* directly.
*
* @param baseUnitMagnitude the magnitude of the measure in terms of its base units.
* @return the ratio measure
*/
@Override
public Measure<? extends PerUnit<N, D>> ofBaseUnits(double baseUnitMagnitude) {
return ofNativeBaseUnits(baseUnitMagnitude);
}
/**
* Creates a new immutable measurement of the given magnitude in terms of the ratio unit. This
* will always return a {@code Per} object and cannot be overridden by subclasses.
*
* @param magnitude the magnitude of the measurement.
* @return the measurement object
* @see #of(double)
*/
public final Per<N, D> ofNative(double magnitude) {
return new ImmutablePer<>(magnitude, toBaseUnits(magnitude), this);
}
/**
* Creates a new immutable measurement of the given magnitude in terms of the ratio unit's base
* unit. This will always return a {@code Per} object and cannot be overridden by subclasses.
*
* @param baseUnitMagnitude the magnitude of the measure in terms of its base units.
* @return the measurement object
* @see #ofBaseUnits(double)
*/
public final Per<N, D> ofNativeBaseUnits(double baseUnitMagnitude) {
return new ImmutablePer<>(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
@SuppressWarnings("unchecked")
public Measure<? extends PerUnit<N, D>> zero() {
return (Measure<? extends PerUnit<N, D>>) super.zero();
}
@Override
@SuppressWarnings("unchecked")
public Measure<? extends PerUnit<N, D>> one() {
return (Measure<? extends PerUnit<N, D>>) super.one();
}
/**
* {@inheritDoc}
*
* <p>Note: When called on an object of type {@code PerUnit} (and <i>not</i> a subclass!), this
* method will always return a {@link edu.wpi.first.units.measure.MutPer} instance.
*
* @param initialMagnitude the starting magnitude of the measure
* @return the ratio measure
*/
@Override
public MutableMeasure<? extends PerUnit<N, D>, ?, ?> mutable(double initialMagnitude) {
return mutableNative(initialMagnitude);
}
/**
* Creates a new mutable measurement of the given magnitude in terms of the ratio unit. This will
* always return a {@code Per} object and cannot be overridden by subclasses.
*
* @param initialMagnitude the starting magnitude of the measure
* @return the ratio measure
* @see #mutable(double)
*/
public final MutPer<N, D> mutableNative(double initialMagnitude) {
return new MutPer<>(initialMagnitude, toBaseUnits(initialMagnitude), this);
}
@Override
public Unit per(TimeUnit time) {
return VelocityUnit.combine(this, time);
}
/**
* Converts a measurement value in terms of another unit to this unit.
*
* @param magnitude the magnitude of the measurement in terms of the other unit
* @param otherUnit the other unit
* @return the value of the measurement in terms of this unit
*/
public double convertFrom(double magnitude, PerUnit<? extends N, ? extends D> otherUnit) {
return fromBaseUnits(otherUnit.toBaseUnits(magnitude));
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!super.equals(o)) {
return false;
}
PerUnit<?, ?> perUnit = (PerUnit<?, ?>) o;
return Objects.equals(m_numerator, perUnit.m_numerator)
&& Objects.equals(m_denominator, perUnit.m_denominator);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), m_numerator, m_denominator);
}
}

View File

@@ -1,29 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
/**
* Unit of power dimension.
*
* <p>This is the base type for units of power dimension. It is also used to specify the dimension
* for {@link Measure}: <code>Measure&lt;Power&gt;</code>.
*
* <p>Actual units (such as {@link Units#Watts} and {@link Units#Horsepower}) can be found in the
* {@link Units} class.
*/
public class Power extends Unit<Power> {
Power(Power baseUnit, double baseUnitEquivalent, String name, String symbol) {
super(baseUnit, baseUnitEquivalent, name, symbol);
}
Power(
Power baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
}

View File

@@ -0,0 +1,164 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
import static edu.wpi.first.units.Units.Joules;
import static edu.wpi.first.units.Units.Seconds;
import edu.wpi.first.units.measure.ImmutablePower;
import edu.wpi.first.units.measure.MutPower;
import edu.wpi.first.units.measure.Power;
/**
* Unit of power dimension.
*
* <p>This is the base type for units of power dimension. It is also used to specify the dimension
* for {@link Measure}: <code>Measure&lt;PowerUnit&gt;</code>.
*
* <p>Actual units (such as {@link Units#Watts} and {@link Units#Horsepower}) can be found in the
* {@link Units} class.
*/
public final class PowerUnit extends PerUnit<EnergyUnit, TimeUnit> {
private static final CombinatoryUnitCache<EnergyUnit, TimeUnit, PowerUnit> cache =
new CombinatoryUnitCache<>(PowerUnit::new);
PowerUnit(EnergyUnit energy, TimeUnit time) {
super(
energy.isBaseUnit() && time.isBaseUnit()
? null
: combine(energy.getBaseUnit(), time.getBaseUnit()),
energy,
time);
}
PowerUnit(
PowerUnit baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
/**
* Combines an energy and a time unit to form a unit of power.
*
* @param energy the unit of energy
* @param period the unit of time
* @return the combined unit of power
*/
public static PowerUnit combine(EnergyUnit energy, TimeUnit period) {
return cache.combine(energy, period);
}
/**
* Combines voltage and current into power.
*
* @param voltage the unit of voltage
* @param current the unit of current
* @return the combined unit of power
*/
public static PowerUnit combine(VoltageUnit voltage, CurrentUnit current) {
return combine(
new EnergyUnit(
Joules,
voltage.toBaseUnits(1) * current.toBaseUnits(1),
voltage.name() + "-" + current.name(),
voltage.symbol() + "*" + current.symbol()),
Seconds);
}
/**
* Combines voltage and current into power.
*
* @param current the unit of current
* @param voltage the unit of voltage
* @return the combined unit of power
*/
public static PowerUnit combine(CurrentUnit current, VoltageUnit voltage) {
return combine(voltage, current);
}
/**
* Combines angular velocity and torque into power. Useful when dealing with motors and flywheels.
*
* @param angularVelocity the unit of angular velocity
* @param torque the unit of torque
* @return the combined unit of power
*/
public static PowerUnit combine(AngularVelocityUnit angularVelocity, TorqueUnit torque) {
return combine(
new EnergyUnit(Joules, angularVelocity.toBaseUnits(1) * torque.toBaseUnits(1), "", ""),
Seconds);
}
/**
* Combines angular velocity and torque into power. Useful when dealing with motors and flywheels.
*
* @param torque the unit of torque
* @param angularVelocity the unit of angular velocity
* @return the combined unit of power
*/
public static PowerUnit combine(TorqueUnit torque, AngularVelocityUnit angularVelocity) {
return combine(angularVelocity, torque);
}
@Override
public PowerUnit getBaseUnit() {
return (PowerUnit) super.getBaseUnit();
}
@Override
public Power of(double magnitude) {
return new ImmutablePower(magnitude, toBaseUnits(magnitude), this);
}
@Override
public Power ofBaseUnits(double baseUnitMagnitude) {
return new ImmutablePower(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public Power zero() {
return (Power) super.zero();
}
@Override
public Power one() {
return (Power) super.one();
}
@Override
public MutPower mutable(double initialMagnitude) {
return new MutPower(initialMagnitude, toBaseUnits(initialMagnitude), this);
}
@Override
public VelocityUnit<PowerUnit> per(TimeUnit time) {
return VelocityUnit.combine(this, time);
}
/**
* Creates a ratio unit between this unit and an arbitrary other unit.
*
* @param other the other unit
* @param <U> the type of the other unit
* @return the ratio unit
*/
public <U extends Unit> PerUnit<PowerUnit, U> per(U other) {
return PerUnit.combine(this, other);
}
/**
* Converts a measurement value in terms of another power unit to this unit.
*
* @param magnitude the magnitude of the measurement in terms of the other power unit
* @param otherUnit the other power unit
* @return the value of the measurement in terms of this unit
*/
public double convertFrom(double magnitude, PowerUnit otherUnit) {
return fromBaseUnits(otherUnit.toBaseUnits(magnitude));
}
}

View File

@@ -1,25 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
/**
* Unit of temperature dimension.
*
* <p>This is the base type for units of temperature dimension. It is also used to specify the
* dimension for {@link Measure}: <code>Measure&lt;Temperature&gt;</code>.
*
* <p>Actual units (such as {@link Units#Celsius} and {@link Units#Fahrenheit}) can be found in the
* {@link Units} class.
*/
public class Temperature extends Unit<Temperature> {
Temperature(
Temperature baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
}

View File

@@ -0,0 +1,86 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
import edu.wpi.first.units.measure.ImmutableTemperature;
import edu.wpi.first.units.measure.MutTemperature;
import edu.wpi.first.units.measure.Temperature;
/**
* Unit of temperature dimension.
*
* <p>This is the base type for units of temperature dimension. It is also used to specify the
* dimension for {@link Measure}: <code>Measure&lt;TemperatureUnit&gt;</code>.
*
* <p>Actual units (such as {@link Units#Celsius} and {@link Units#Fahrenheit}) can be found in the
* {@link Units} class.
*/
public final class TemperatureUnit extends Unit {
TemperatureUnit(
TemperatureUnit baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
@Override
public TemperatureUnit getBaseUnit() {
return (TemperatureUnit) super.getBaseUnit();
}
@Override
public Temperature of(double magnitude) {
return new ImmutableTemperature(magnitude, toBaseUnits(magnitude), this);
}
@Override
public Temperature ofBaseUnits(double baseUnitMagnitude) {
return new ImmutableTemperature(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public Temperature zero() {
return (Temperature) super.zero();
}
@Override
public Temperature one() {
return (Temperature) super.one();
}
@Override
public MutTemperature mutable(double initialMagnitude) {
return new MutTemperature(initialMagnitude, toBaseUnits(initialMagnitude), this);
}
@Override
public VelocityUnit<TemperatureUnit> per(TimeUnit period) {
return VelocityUnit.combine(this, period);
}
/**
* Creates a ratio unit between this unit and an arbitrary other unit.
*
* @param other the other unit
* @param <U> the type of the other unit
* @return the ratio unit
*/
public <U extends Unit> PerUnit<TemperatureUnit, U> per(U other) {
return PerUnit.combine(this, other);
}
/**
* Converts a measurement value in terms of another temperature unit to this unit.
*
* @param magnitude the magnitude of the measurement in terms of the other temperature unit
* @param otherUnit the other temperature unit
* @return the value of the measurement in terms of this unit
*/
public double convertFrom(double magnitude, TemperatureUnit otherUnit) {
return fromBaseUnits(otherUnit.toBaseUnits(magnitude));
}
}

View File

@@ -1,29 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
/**
* Unit of time dimension.
*
* <p>This is the base type for units of time dimension. It is also used to specify the dimension
* for {@link Measure}: <code>Measure&lt;Time&gt;</code>.
*
* <p>Actual units (such as {@link Units#Seconds} and {@link Units#Milliseconds}) can be found in
* the {@link Units} class.
*/
public class Time extends Unit<Time> {
Time(Time baseUnit, double baseUnitEquivalent, String name, String symbol) {
super(baseUnit, baseUnitEquivalent, name, symbol);
}
Time(
Time baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
}

View File

@@ -0,0 +1,102 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
import edu.wpi.first.units.measure.ImmutableTime;
import edu.wpi.first.units.measure.MutTime;
import edu.wpi.first.units.measure.Time;
/**
* Unit of time dimension.
*
* <p>This is the base type for units of time dimension. It is also used to specify the dimension
* for {@link Measure}: <code>Measure&lt;TimeUnit&gt;</code>.
*
* <p>Actual units (such as {@link Units#Seconds} and {@link Units#Milliseconds}) can be found in
* the {@link Units} class.
*/
public final class TimeUnit extends Unit {
TimeUnit(TimeUnit baseUnit, double baseUnitEquivalent, String name, String symbol) {
super(baseUnit, baseUnitEquivalent, name, symbol);
}
TimeUnit(
TimeUnit baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
@Override
public TimeUnit getBaseUnit() {
return (TimeUnit) super.getBaseUnit();
}
/**
* Creates a dimensionless unit corresponding to the scale factor between this and another unit of
* time.
*
* @param other the other unit of time
* @return the result
*/
@Override
public DimensionlessUnit per(TimeUnit other) {
return Units.derive(Units.Value)
.toBase(this.getConverterToBase().div(other.getConverterToBase()))
.fromBase(other.getConverterFromBase().div(this.getConverterFromBase()))
.named(this.name() + " per " + other.name())
.symbol(this.symbol() + "/" + other.symbol())
.make();
}
/**
* Creates a ratio unit between this unit and an arbitrary other unit.
*
* @param other the other unit
* @param <U> the type of the other unit
* @return the ratio unit
*/
public <U extends Unit> PerUnit<TimeUnit, U> per(U other) {
return PerUnit.combine(this, other);
}
/**
* Converts a measurement value in terms of another unit to this unit.
*
* @param magnitude the magnitude of the measurement in terms of the other unit
* @param otherUnit the other unit
* @return the value of the measurement in terms of this unit
*/
public double convertFrom(double magnitude, TimeUnit otherUnit) {
return fromBaseUnits(otherUnit.toBaseUnits(magnitude));
}
@Override
public Time of(double magnitude) {
return new ImmutableTime(magnitude, toBaseUnits(magnitude), this);
}
@Override
public Time ofBaseUnits(double baseUnitMagnitude) {
return new ImmutableTime(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public Time zero() {
return (Time) super.zero();
}
@Override
public Time one() {
return (Time) super.one();
}
@Override
public MutTime mutable(double initialMagnitude) {
return new MutTime(initialMagnitude, toBaseUnits(initialMagnitude), this);
}
}

View File

@@ -0,0 +1,101 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
import edu.wpi.first.units.measure.ImmutableTorque;
import edu.wpi.first.units.measure.MutTorque;
import edu.wpi.first.units.measure.Torque;
/** A unit of torque like {@link edu.wpi.first.units.Units#NewtonMeters}. */
public final class TorqueUnit extends MultUnit<DistanceUnit, ForceUnit> {
private static final CombinatoryUnitCache<DistanceUnit, ForceUnit, TorqueUnit> cache =
new CombinatoryUnitCache<>(TorqueUnit::new);
TorqueUnit(DistanceUnit distanceUnit, ForceUnit forceUnit) {
super(
distanceUnit.isBaseUnit() && forceUnit.isBaseUnit()
? null
: combine(distanceUnit.getBaseUnit(), forceUnit.getBaseUnit()),
distanceUnit,
forceUnit);
}
TorqueUnit(
MultUnit<DistanceUnit, ForceUnit> baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
/**
* Combines a unit of distance and force to create a unit of torque.
*
* @param distance the distance unit
* @param force the force unit
* @return the combined torque unit
*/
public static TorqueUnit combine(DistanceUnit distance, ForceUnit force) {
return cache.combine(distance, force);
}
@Override
public TorqueUnit getBaseUnit() {
return (TorqueUnit) super.getBaseUnit();
}
@Override
public Torque of(double magnitude) {
return new ImmutableTorque(magnitude, toBaseUnits(magnitude), this);
}
@Override
public Torque ofBaseUnits(double baseUnitMagnitude) {
return new ImmutableTorque(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public Torque zero() {
return (Torque) super.zero();
}
@Override
public Torque one() {
return (Torque) super.one();
}
@Override
public MutTorque mutable(double initialMagnitude) {
return new MutTorque(initialMagnitude, toBaseUnits(initialMagnitude), this);
}
@Override
public VelocityUnit<TorqueUnit> per(TimeUnit time) {
return VelocityUnit.combine(this, time);
}
/**
* Creates a ratio unit between this unit and an arbitrary other unit.
*
* @param other the other unit
* @param <U> the type of the other unit
* @return the ratio unit
*/
public <U extends Unit> PerUnit<TorqueUnit, U> per(U other) {
return PerUnit.combine(this, other);
}
/**
* Converts a measurement value in terms of another unit to this unit.
*
* @param magnitude the magnitude of the measurement in terms of the other unit
* @param otherUnit the other unit
* @return the value of the measurement in terms of this unit
*/
public double convertFrom(double magnitude, TorqueUnit otherUnit) {
return fromBaseUnits(otherUnit.toBaseUnits(magnitude));
}
}

View File

@@ -11,21 +11,19 @@ import java.util.Objects;
*
* <p>This is the base class for units. Actual units (such as {@link Units#Grams} and {@link
* Units#Meters}) can be found in the {@link Units} class.
*
* @param <U> the self type, e.g. {@code class SomeUnit extends Unit<SomeUnit>}
*/
public class Unit<U extends Unit<U>> {
public abstract class Unit {
private final UnaryFunction m_toBaseConverter;
private final UnaryFunction m_fromBaseConverter;
private final U m_baseUnit;
private Measure<U> m_zero;
private Measure<U> m_one;
private final Unit m_baseUnit;
private final String m_name;
private final String m_symbol;
private final Measure<?> m_zero;
private final Measure<?> m_one;
/**
* Creates a new unit defined by its relationship to some base unit.
*
@@ -36,18 +34,21 @@ public class Unit<U extends Unit<U>> {
* @param name the name of the unit. This should be a singular noun (so "Meter", not "Meters")
* @param symbol the short symbol for the unit, such as "m" for meters or "lb." for pounds
*/
@SuppressWarnings("unchecked")
@SuppressWarnings("this-escape")
protected Unit(
U baseUnit,
Unit baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
m_baseUnit = baseUnit == null ? (U) this : baseUnit;
m_baseUnit = baseUnit == null ? this : baseUnit;
m_toBaseConverter = Objects.requireNonNull(toBaseConverter);
m_fromBaseConverter = Objects.requireNonNull(fromBaseConverter);
m_name = Objects.requireNonNull(name);
m_symbol = Objects.requireNonNull(symbol);
m_zero = of(0);
m_one = of(1);
}
/**
@@ -60,14 +61,79 @@ public class Unit<U extends Unit<U>> {
* @param name the name of the unit. This should be a singular noun (so "Meter", not "Meters")
* @param symbol the short symbol for the unit, such as "m" for meters or "lb." for pounds
*/
protected Unit(U baseUnit, double baseUnitEquivalent, String name, String symbol) {
protected Unit(Unit baseUnit, double baseUnitEquivalent, String name, String symbol) {
this(baseUnit, x -> x * baseUnitEquivalent, x -> x / baseUnitEquivalent, name, symbol);
}
/**
* Creates a new immutable measurement of the given magnitude in terms of this unit.
* Implementations are <strong>strongly</strong> recommended to sharpen the return type to a
* unit-specific measurement implementation.
*
* @param magnitude the magnitude of the measurement.
* @return the measurement object
*/
public abstract Measure<?> of(double magnitude);
/**
* Creates a new immutable measurement of the given magnitude in terms of this unit's base unit.
* Implementations are <strong>strongly</strong> recommended to sharpen the return type to a
* unit-specific measurement implementation.
*
* @param baseUnitMagnitude the magnitude in terms of the base unit
* @return the measurement object
*/
public abstract Measure<?> ofBaseUnits(double baseUnitMagnitude);
/**
* Creates a new mutable measurement that is initialized to the given magnitude in terms of this
* unit. Implementations are <strong>strongly</strong> recommended to sharpen the return type to a
* unit-specific measurement implementation.
*
* @param initialMagnitude the initial magnitude of the mutable measurement
* @return the mutable measurement object
*/
public abstract MutableMeasure<?, ?, ?> mutable(double initialMagnitude);
/**
* Gets a measure of zero magnitude in terms of this unit. The returned object is guaranteed to be
* of the same type returned by {@link #of(double)}. Subclasses are encouraged to override this
* method to sharpen the return type.
*
* @return a zero-magnitude measure of this unit
*/
public Measure<?> zero() {
return m_zero;
}
/**
* Gets a measure with a magnitude of 1.0 in terms of this unit. The returned object is guaranteed
* to be of the same type returned by {@link #of(double)}. Subclasses are encouraged to override
* this method to sharpen the return type.
*
* @return a measure of magnitude 1.0 in terms of this unit
*/
public Measure<?> one() {
return m_one;
}
/**
* Combines this unit with a unit of time. This often - but not always - results in a velocity.
* Subclasses should sharpen the return type to be unit-specific.
*
* @param time the unit of time
* @return the combined unit
*/
public abstract Unit per(TimeUnit time);
/**
* Gets the base unit of measurement that this unit is derived from. If the unit is the base unit,
* the unit will be returned.
*
* <p><strong>NOTE:</strong> Subclasses <strong>must</strong> override this method to provide the
* correct return type. Failing to do say will make unit combinations that use it break at
* runtime!
*
* <pre><code>
* Unit baseUnit = new Unit(null, ...);
* baseUnit.getBaseUnit(); // returns baseUnit
@@ -78,7 +144,7 @@ public class Unit<U extends Unit<U>> {
*
* @return the base unit
*/
public U getBaseUnit() {
public Unit getBaseUnit() {
return m_baseUnit;
}
@@ -111,27 +177,6 @@ public class Unit<U extends Unit<U>> {
return m_toBaseConverter.apply(valueInNativeUnits);
}
/**
* Converts a magnitude in terms of another unit of the same dimension to a magnitude in terms of
* this unit.
*
* <pre>
* Inches.convertFrom(12, Feet) // 144.0
* Kilograms.convertFrom(2.2, Pounds) // 0.9979024
* </pre>
*
* @param magnitude a magnitude measured in another unit
* @param otherUnit the unit to convert the magnitude to
* @return the corresponding value in terms of this unit.
*/
public double convertFrom(double magnitude, Unit<U> otherUnit) {
if (this.equivalent(otherUnit)) {
// same unit, don't bother converting
return magnitude;
}
return this.fromBaseUnits(otherUnit.toBaseUnits(magnitude));
}
/**
* Gets the conversion function used to convert values to base unit terms. This generally
* shouldn't need to be used directly; prefer {@link #toBaseUnits(double)} instead.
@@ -152,113 +197,6 @@ public class Unit<U extends Unit<U>> {
return m_fromBaseConverter;
}
/**
* Creates a new measure of this unit with the given value. The resulting measure is
* <i>immutable</i> and cannot have its value modified.
*
* @param magnitude the magnitude of the measure to create
* @return the measure
*/
public Measure<U> of(double magnitude) {
if (magnitude == 0) {
// reuse static object
return zero();
}
if (magnitude == 1) {
// reuse static object
return one();
}
return ImmutableMeasure.ofRelativeUnits(magnitude, this);
}
/**
* Creates a new measure with a magnitude equal to the given base unit magnitude, converted to be
* in terms of this unit.
*
* @param baseUnitMagnitude the magnitude of the measure in terms of the base unit
* @return the measure
*/
public Measure<U> ofBaseUnits(double baseUnitMagnitude) {
return ImmutableMeasure.ofBaseUnits(baseUnitMagnitude, this);
}
/**
* Gets a measure with a magnitude of 0 in terms of this unit.
*
* @return the zero-valued measure
*/
public Measure<U> zero() {
// lazy init because 'this' is null in object initialization
if (m_zero == null) {
m_zero = ImmutableMeasure.ofRelativeUnits(0, this);
}
return m_zero;
}
/**
* Gets a measure with a magnitude of 1 in terms of this unit.
*
* @return the 1-valued measure
*/
public Measure<U> one() {
// lazy init because 'this' is null in object initialization
if (m_one == null) {
m_one = ImmutableMeasure.ofRelativeUnits(1, this);
}
return m_one;
}
/**
* Creates a velocity unit derived from this one. Can be chained to denote velocity, acceleration,
* jerk, etc.
*
* <pre>
* Meters.per(Second) // linear velocity
* Kilograms.per(Second) // mass flow
* Feet.per(Second).per(Second).of(32) // roughly 1G of acceleration
* </pre>
*
* @param period the time period of the velocity, such as seconds or milliseconds
* @return a velocity unit corresponding to the rate of change of this unit over time
*/
public Velocity<U> per(Time period) {
return Velocity.combine(this, period);
}
/**
* Takes this unit and creates a new proportional unit where this unit is the numerator and the
* given denominator is the denominator.
*
* <pre>
* Volts.per(Meter) // V/m
* </pre>
*
* @param <D> the type of the denominator units
* @param denominator the denominator of the proportional unit
* @return a combined proportional unit
*/
@SuppressWarnings("unchecked")
public <D extends Unit<D>> Per<U, D> per(D denominator) {
return Per.combine((U) this, denominator);
}
/**
* Takes this unit and creates a new combinatory unit equivalent to this unit multiplied by
* another.
*
* <pre>
* Volts.mult(Meter) // V*m
* </pre>
*
* @param <U2> the type of the unit to multiply by
* @param other the unit to multiply by
* @return a combined unit equivalent to this unit multiplied by the other
*/
@SuppressWarnings("unchecked")
public <U2 extends Unit<U2>> Mult<U, U2> mult(U2 other) {
return Mult.combine((U) this, other);
}
/**
* Checks if this unit is equivalent to another one. Equivalence is determined by both units
* having the same base type and treat the same base unit magnitude as the same magnitude in their
@@ -267,7 +205,7 @@ public class Unit<U extends Unit<U>> {
* @param other the unit to compare to.
* @return true if both units are equivalent, false if not
*/
public boolean equivalent(Unit<?> other) {
public boolean equivalent(Unit other) {
if (!getClass().equals(other.getClass())) {
// different unit types, not compatible
return false;
@@ -287,7 +225,7 @@ public class Unit<U extends Unit<U>> {
@Override
public boolean equals(Object o) {
return this == o
|| o instanceof Unit<?> that
|| o instanceof Unit that
&& m_name.equals(that.m_name)
&& m_symbol.equals(that.m_symbol)
&& this.equivalent(that);

View File

@@ -18,7 +18,7 @@ import java.util.Objects;
*
* @param <U> the type of the unit
*/
public final class UnitBuilder<U extends Unit<U>> {
public final class UnitBuilder<U extends Unit> {
private final U m_base;
private UnaryFunction m_fromBase = UnaryFunction.IDENTITY;
private UnaryFunction m_toBase = UnaryFunction.IDENTITY;
@@ -191,7 +191,7 @@ public final class UnitBuilder<U extends Unit<U>> {
* @param <U> the type of the unit
*/
@FunctionalInterface
public interface UnitConstructorFunction<U extends Unit<U>> {
public interface UnitConstructorFunction<U extends Unit> {
/**
* Creates a new unit instance based on its relation to the base unit of measure.
*
@@ -220,6 +220,7 @@ public final class UnitBuilder<U extends Unit<U>> {
* @return the new derived unit
* @throws NullPointerException if the unit conversions, unit name, or unit symbol were not set
*/
@SuppressWarnings("unchecked")
public U make(UnitConstructorFunction<U> constructor) {
Objects.requireNonNull(m_fromBase, "fromBase function was not set");
Objects.requireNonNull(m_toBase, "toBase function was not set");
@@ -227,7 +228,7 @@ public final class UnitBuilder<U extends Unit<U>> {
Objects.requireNonNull(m_symbol, "new unit symbol was not set");
return constructor.create(
m_base.getBaseUnit(),
(U) m_base.getBaseUnit(),
m_toBase.pipeTo(m_base.getConverterToBase()),
m_base.getConverterFromBase().pipeTo(m_fromBase),
m_name,
@@ -242,7 +243,6 @@ public final class UnitBuilder<U extends Unit<U>> {
* @throws RuntimeException if the base unit does not define a constructor accepting the
* conversion functions, unit name, and unit symbol - in that order
*/
@SuppressWarnings({"PMD.AvoidAccessibilityAlteration", "unchecked"})
public U make() {
return make(
(baseUnit, toBaseUnits, fromBaseUnits, name, symbol) -> {
@@ -251,7 +251,7 @@ public final class UnitBuilder<U extends Unit<U>> {
try {
var ctor = getConstructor(baseUnit);
return (U) ctor.newInstance(baseUnit, toBaseUnits, fromBaseUnits, name, symbol);
return ctor.newInstance(baseUnit, toBaseUnits, fromBaseUnits, name, symbol);
} catch (InstantiationException e) {
throw new RuntimeException("Could not instantiate class " + baseClass.getName(), e);
} catch (IllegalAccessException e) {
@@ -272,7 +272,7 @@ public final class UnitBuilder<U extends Unit<U>> {
}
@SuppressWarnings({"unchecked", "PMD.AvoidAccessibilityAlteration"})
private static <U extends Unit<U>> Constructor<? extends Unit<U>> getConstructor(U baseUnit)
private static <U extends Unit> Constructor<? extends U> getConstructor(U baseUnit)
throws NoSuchMethodException {
var baseClass = baseUnit.getClass();
@@ -288,6 +288,6 @@ public final class UnitBuilder<U extends Unit<U>> {
// and protected constructors
ctor.setAccessible(true);
return (Constructor<? extends Unit<U>>) ctor;
return (Constructor<? extends U>) ctor;
}
}

View File

@@ -14,365 +14,478 @@ public final class Units {
// Pseudo-classes describing the more common units of measure.
// Distance
// Unitless
/** A dimensionless unit that performs no scaling whatsoever. */
public static final DimensionlessUnit Value = BaseUnits.Value;
/**
* A dimensionless unit equal to to 1/100th of a {@link #Value}. A measurement of {@code
* Percent.of(42)} would be equivalent to {@code Value.of(0.42)}.
*/
public static final DimensionlessUnit Percent =
derive(Value).splitInto(100).named("Percent").symbol("%").make();
// DistanceUnit
/** The base unit of distance. */
public static final Distance Meters = BaseUnits.Distance;
public static final DistanceUnit Meters = BaseUnits.DistanceUnit;
/** The base unit of distance. */
public static final Distance Meter = Meters; // alias
public static final DistanceUnit Meter = Meters; // alias
/** 1/1000 of a {@link #Meter}. */
public static final Distance Millimeters = Milli(Meters, "Millimeter", "mm");
public static final DistanceUnit Millimeters = Milli(Meters, "Millimeter", "mm");
/** 1/1000 of a {@link #Meter}. */
public static final Distance Millimeter = Millimeters; // alias
public static final DistanceUnit Millimeter = Millimeters; // alias
/** 1/100 of a {@link #Meter}. */
public static final Distance Centimeters =
public static final DistanceUnit Centimeters =
derive(Meters).splitInto(100).named("Centimeter").symbol("cm").make();
/** 1/100 of a {@link #Meter}. */
public static final Distance Centimeter = Centimeters; // alias
public static final DistanceUnit Centimeter = Centimeters; // alias
/** 25.4/1000 of a {@link #Meter} and 1/12 of a {@link #Foot}. */
public static final Distance Inches =
public static final DistanceUnit Inches =
derive(Millimeters).aggregate(25.4).named("Inch").symbol("in").make();
/** 25.4/1000 of a {@link #Meter} and 1/12 of a {@link #Foot}. */
public static final Distance Inch = Inches; // alias
public static final DistanceUnit Inch = Inches; // alias
/** 304.8/1000 of a {@link #Meter}, or 12 {@link #Inches}. */
public static final Distance Feet =
public static final DistanceUnit Feet =
derive(Inches).aggregate(12).named("Foot").symbol("ft").make();
/** 304.8/1000 of a {@link #Meter}, or 12 {@link #Inches}. */
public static final Distance Foot = Feet; // alias
public static final DistanceUnit Foot = Feet; // alias
// Time
// TimeUnit
/** The base unit of time. */
public static final Time Seconds = BaseUnits.Time;
public static final TimeUnit Seconds = BaseUnits.TimeUnit;
/** Alias for {@link #Seconds} to make combined unit definitions read more smoothly. */
public static final Time Second = Seconds; // singularized alias
public static final TimeUnit Second = Seconds; // singularized alias
/** 1/1000 of a {@link #Seconds Second}. */
public static final Time Milliseconds = Milli(Seconds);
public static final TimeUnit Milliseconds = Milli(Seconds);
/** Alias for {@link #Milliseconds} to make combined unit definitions read more smoothly. */
public static final Time Millisecond = Milliseconds; // singularized alias
public static final TimeUnit Millisecond = Milliseconds; // singularized alias
/** 1/1,000,000 of a {@link #Seconds Second}. */
public static final Time Microseconds = Micro(Seconds);
public static final TimeUnit Microseconds = Micro(Seconds);
/** Alias for {@link #Microseconds} to make combined unit definitions read more smoothly. */
public static final Time Microsecond = Microseconds; // singularized alias
public static final TimeUnit Microsecond = Microseconds; // singularized alias
/** 60 {@link #Seconds}. */
public static final Time Minutes =
public static final TimeUnit Minutes =
derive(Seconds).aggregate(60).named("Minute").symbol("min").make();
/** Alias for {@link #Minutes} to make combined unit definitions read more smoothly. */
public static final Time Minute = Minutes; // singularized alias
public static final TimeUnit Minute = Minutes; // singularized alias
// Angle
// AngleUnit
/**
* The base SI unit of angle, represented by the distance that the radius of a unit circle can
* The standard SI unit of angle, represented by the distance that the radius of a unit circle can
* wrap around its circumference.
*/
public static final Angle Radians = BaseUnits.Angle;
public static final AngleUnit Radians = BaseUnits.AngleUnit;
/**
* The base SI unit of angle, represented by the distance that the radius of a unit circle can
* The standard SI unit of angle, represented by the distance that the radius of a unit circle can
* wrap around its circumference.
*/
public static final Angle Radian = Radians; // alias
public static final AngleUnit Radian = Radians; // alias
/**
* A single turn of an object around an external axis. Numerically equivalent to {@link
* #Rotations}, but may be semantically more expressive in certain scenarios.
*/
public static final Angle Revolutions =
public static final AngleUnit Revolutions =
derive(Radians).aggregate(2 * Math.PI).named("Revolution").symbol("R").make();
/**
* A single turn of an object around an external axis. Numerically equivalent to a {@link
* #Rotation}, but may be semantically more expressive in certain scenarios.
*/
public static final Angle Revolution = Revolutions; // alias
public static final AngleUnit Revolution = Revolutions; // alias
/**
* A single turn of an object around an internal axis. Numerically equivalent to {@link
* #Revolutions}, but may be semantically more expressive in certain scenarios.
*/
public static final Angle Rotations = derive(Revolutions).named("Rotation").symbol("R").make();
public static final AngleUnit Rotations =
derive(Revolutions).named("Rotation").symbol("R").make();
/**
* A single turn of an object around an internal axis. Numerically equivalent to a {@link
* #Revolution}, but may be semantically more expressive in certain scenarios.
*/
public static final Angle Rotation = Rotations; // alias
public static final AngleUnit Rotation = Rotations; // alias
/** 1/360 of a turn around a circle, or 1/57.3 {@link #Radians}. */
public static final Angle Degrees =
public static final AngleUnit Degrees =
derive(Revolutions).splitInto(360).named("Degree").symbol("°").make();
/** 1/360 of a turn around a circle, or 1/57.3 {@link #Radians}. */
public static final Angle Degree = Degrees; // alias
public static final AngleUnit Degree = Degrees; // alias
// Velocity
// VelocityUnit
/**
* The standard SI unit of linear velocity, equivalent to travelling at a rate of one {@link
* #Meters Meter} per {@link #Second}.
*/
public static final Velocity<Distance> MetersPerSecond = Meters.per(Second);
public static final LinearVelocityUnit MetersPerSecond = Meters.per(Second);
/**
* A unit of linear velocity equivalent to travelling at a rate one {@link #Feet Foot} per {@link
* #Second}.
*/
public static final Velocity<Distance> FeetPerSecond = Feet.per(Second);
public static final LinearVelocityUnit FeetPerSecond = Feet.per(Second);
/**
* A unit of linear velocity equivalent to travelling at a rate of one {@link #Inches Inch} per
* {@link #Second}.
*/
public static final Velocity<Distance> InchesPerSecond = Inches.per(Second);
public static final LinearVelocityUnit InchesPerSecond = Inches.per(Second);
/**
* A unit of angular velocity equivalent to spinning at a rate of one {@link #Revolutions
* Revolution} per {@link #Second}.
*/
public static final Velocity<Angle> RevolutionsPerSecond = Revolutions.per(Second);
public static final AngularVelocityUnit RevolutionsPerSecond = Revolutions.per(Second);
/**
* A unit of angular velocity equivalent to spinning at a rate of one {@link #Rotations Rotation}
* per {@link #Second}.
*/
public static final Velocity<Angle> RotationsPerSecond = Rotations.per(Second);
public static final AngularVelocityUnit RotationsPerSecond = Rotations.per(Second);
/**
* A unit of angular velocity equivalent to spinning at a rate of one {@link #Rotations Rotation}
* per {@link #Minute}. Motor spec sheets often list maximum speeds in terms of RPM.
*/
public static final Velocity<Angle> RPM = Rotations.per(Minute);
public static final AngularVelocityUnit RPM = Rotations.per(Minute);
/**
* The standard SI unit of angular velocity, equivalent to spinning at a rate of one {@link
* #Radians Radian} per {@link #Second}.
*/
public static final Velocity<Angle> RadiansPerSecond = Radians.per(Second);
public static final AngularVelocityUnit RadiansPerSecond = Radians.per(Second);
/**
* A unit of angular velocity equivalent to spinning at a rate of one {@link #Degrees Degree} per
* {@link #Second}.
*/
public static final Velocity<Angle> DegreesPerSecond = Degrees.per(Second);
public static final AngularVelocityUnit DegreesPerSecond = Degrees.per(Second);
/**
* The standard SI unit of frequency, equivalent to a periodic signal repeating once every {@link
* #Second}.
*/
public static final FrequencyUnit Hertz =
derive(Value.per(Second)).named("Hertz").symbol("hz").make();
/** 1/1000th of a {@link #Hertz}. */
public static final FrequencyUnit Millihertz = Milli(Hertz);
// Acceleration
/**
* The standard SI unit of linear acceleration, equivalent to accelerating at a rate of one {@link
* #Meters Meter} per {@link #Second} every second.
*/
public static final Velocity<Velocity<Distance>> MetersPerSecondPerSecond =
MetersPerSecond.per(Second);
public static final LinearAccelerationUnit MetersPerSecondPerSecond = MetersPerSecond.per(Second);
/**
* A unit of linear acceleration equivalent to accelerating at a rate of one {@link #Foot Foot}
* per {@link #Second} every second.
*/
public static final Velocity<Velocity<Distance>> FeetPerSecondPerSecond =
FeetPerSecond.per(Second);
public static final LinearAccelerationUnit FeetPerSecondPerSecond = FeetPerSecond.per(Second);
/**
* A unit of angular acceleration equivalent to accelerating at a rate of one {@link #Rotations
* Rotation} per {@link #Second} every second.
*/
public static final Velocity<Velocity<Angle>> RotationsPerSecondPerSecond =
public static final AngularAccelerationUnit RotationsPerSecondPerSecond =
RotationsPerSecond.per(Second);
/**
* The standard SI unit of angular acceleration, equivalent to accelerating at a rate of one
* {@link #Radians Radian} per {@link #Second} every second.
*/
public static final Velocity<Velocity<Angle>> RadiansPerSecondPerSecond =
public static final AngularAccelerationUnit RadiansPerSecondPerSecond =
RadiansPerSecond.per(Second);
/**
* A unit of angular acceleration equivalent to accelerating at a rate of one {@link #Degrees
* Degree} per {@link #Second} every second.
*/
public static final Velocity<Velocity<Angle>> DegreesPerSecondPerSecond =
public static final AngularAccelerationUnit DegreesPerSecondPerSecond =
DegreesPerSecond.per(Second);
/**
* A unit of acceleration equivalent to the pull of gravity on an object at sea level on Earth.
*/
public static final Velocity<Velocity<Distance>> Gs =
public static final LinearAccelerationUnit Gs =
derive(MetersPerSecondPerSecond).aggregate(9.80665).named("G").symbol("G").make();
// Mass
/** The base SI unit of mass. */
public static final Mass Kilograms = BaseUnits.Mass;
// MassUnit
/** The standard SI unit of mass. */
public static final MassUnit Kilograms = BaseUnits.MassUnit;
/** The base SI unit of mass. */
public static final Mass Kilogram = Kilograms; // alias
/** The standard SI unit of mass. */
public static final MassUnit Kilogram = Kilograms; // alias
/** 1/1000 of a {@link #Kilogram}. */
public static final Mass Grams = Milli(Kilograms, "Gram", "g");
public static final MassUnit Grams = Milli(Kilograms, "Gram", "g");
/** 1/1000 of a {@link #Kilogram}. */
public static final Mass Gram = Grams; // alias
public static final MassUnit Gram = Grams; // alias
/**
* A unit of mass equivalent to approximately 453 {@link #Grams}. This is <i>not</i> equivalent to
* pounds-force, which is the amount of force required to accelerate an object with one pound of
* mass at a rate of one {@link #Gs G}.
*
* @see #PoundsForce
*/
public static final Mass Pounds =
public static final MassUnit Pounds =
derive(Grams).aggregate(453.592).named("Pound").symbol("lb.").make();
/**
* A unit of mass equivalent to approximately 453 {@link #Grams}. This is <i>not</i> equivalent to
* pounds-force, which is the amount of force required to accelerate an object with one pound of
* mass at a rate of one {@link #Gs G}.
*
* @see #PoundForce
*/
public static final Mass Pound = Pounds; // alias
public static final MassUnit Pound = Pounds; // alias
/** 1/16 of a {@link #Pound}. */
public static final Mass Ounces =
public static final MassUnit Ounces =
derive(Pounds).splitInto(16).named("Ounce").symbol("oz.").make();
/** 1/16 of a {@link #Pound}. */
public static final Mass Ounce = Ounces; // alias
public static final MassUnit Ounce = Ounces; // alias
// Force
/**
* The standard unit of force, equivalent to accelerating a mass of one {@link #Kilogram} at a
* rate of one {@link #MetersPerSecondPerSecond meter per second per second}.
*/
public static final ForceUnit Newtons =
derive(Kilograms.mult(MetersPerSecondPerSecond)).named("Newton").symbol("N").make();
/**
* The standard unit of force, equivalent to the standard force of gravity applied to a one {@link
* #Kilogram} mass.
*/
public static final ForceUnit Newton = Newtons;
/**
* The standard Imperial unit of force, equivalent to the standard force of gravity applied to a
* one {@link #Pound} mass.
*/
public static final ForceUnit PoundsForce =
derive(Pounds.mult(Gs)).named("Pound-force").symbol("lbsf.").make();
/**
* The standard Imperial unit of force, equivalent to the standard force of gravity applied to a
* one {@link #Pound} mass.
*/
public static final ForceUnit PoundForce = PoundsForce;
/**
* 1/16th of {@link #PoundsForce}, equivalent to the standard force of gravity applied to a one
* {@link #Ounce} mass.
*/
public static final ForceUnit OuncesForce =
derive(Ounces.mult(Gs)).named("Ounce-force").symbol("ozf").make();
/**
* 1/16th of {@link #PoundsForce}, equivalent to the standard force of gravity applied to a one
* {@link #Ounce} mass.
*/
public static final ForceUnit OunceForce = OuncesForce;
// Torque
/** The standard SI unit for torque. */
public static final TorqueUnit NewtonMeters = Meters.multAsTorque(Newtons);
/** The standard SI unit for torque. */
public static final TorqueUnit NewtonMeter = NewtonMeters;
/**
* The equivalent of one {@link #PoundsForce pound of force} applied to an object one {@link
* #Foot} away from its center of rotation.
*/
public static final TorqueUnit PoundFeet = Feet.multAsTorque(PoundsForce);
/**
* The equivalent of one {@link #PoundsForce pound of force} applied to an object one {@link
* #Foot} away from its center of rotation.
*/
public static final TorqueUnit PoundFoot = PoundFeet;
/**
* The equivalent of one {@link #PoundsForce pound of force} applied to an object one {@link
* #Inch} away from its center of rotation.
*/
public static final TorqueUnit PoundInches = Inches.multAsTorque(PoundsForce);
/**
* The equivalent of one {@link #PoundsForce pound of force} applied to an object one {@link
* #Inch} away from its center of rotation.
*/
public static final TorqueUnit PoundInch = PoundInches;
/**
* The equivalent of one {@link #OunceForce ounce of force} applied to an object one {@link #Inch}
* away from its center of rotation.
*/
public static final TorqueUnit OunceInches = Inches.multAsTorque(OuncesForce);
/**
* The equivalent of one {@link #OunceForce ounce of force} applied to an object one {@link #Inch}
* away from its center of rotation.
*/
public static final TorqueUnit OunceInch = OunceInches;
// Linear momentum
/**
* The standard SI unit for linear momentum, equivalent to a one {@link #Kilogram} mass moving at
* one {@link #MetersPerSecond}.
*/
public static final LinearMomentumUnit KilogramMetersPerSecond = Kilograms.mult(MetersPerSecond);
// Angular momentum
/** The standard SI unit for angular momentum. */
public static final AngularMomentumUnit KilogramMetersSquaredPerSecond =
KilogramMetersPerSecond.mult(Meters);
// Moment of Inertia
/** The base SI unit for moment of inertia. */
public static final Mult<Mult<Mass, Distance>, Distance> KilogramSquareMeters =
Kilograms.mult(Meters).mult(Meters);
// Unitless
/** A dimensionless unit that performs no scaling whatsoever. */
public static final Dimensionless Value = BaseUnits.Value;
/** The standard SI unit for moment of inertia. */
public static final MomentOfInertiaUnit KilogramSquareMeters =
KilogramMetersSquaredPerSecond.mult(RadiansPerSecond);
/**
* A dimensionless unit equal to to 1/100th of a {@link #Value}. A measurement of {@code
* Percent.of(42)} would be equivalent to {@code Value.of(0.42)}.
*/
public static final Dimensionless Percent =
derive(Value).splitInto(100).named("Percent").symbol("%").make();
// Voltage
// VoltageUnit
/** The base unit of electric potential. */
public static final Voltage Volts = BaseUnits.Voltage;
public static final VoltageUnit Volts = BaseUnits.VoltageUnit;
/** The base unit of electric potential. */
public static final Voltage Volt = Volts; // alias
public static final VoltageUnit Volt = Volts; // alias
/**
* 1/1000 of a {@link #Volt}. Useful when dealing with low-voltage applications like LED drivers
* or low-power circuits.
*/
public static final Voltage Millivolts = Milli(Volts);
public static final VoltageUnit Millivolts = Milli(Volts);
/**
* 1/1000 of a {@link #Volt}. Useful when dealing with low-voltage applications like LED drivers
* or low-power circuits.
*/
public static final Voltage Millivolt = Millivolts; // alias
public static final VoltageUnit Millivolt = Millivolts; // alias
// Current
// CurrentUnit
/** The base unit of electrical current. */
public static final Current Amps = BaseUnits.Current;
public static final CurrentUnit Amps = BaseUnits.CurrentUnit;
/** The base unit of electrical current. */
public static final Current Amp = Amps; // alias
public static final CurrentUnit Amp = Amps; // alias
/**
* A unit equal to 1/1000 of an {@link #Amp}. Useful when dealing with low-current applications
* like LED drivers or low-power circuits.
*/
public static final Current Milliamps = Milli(Amps);
public static final CurrentUnit Milliamps = Milli(Amps);
/**
* A unit equal to 1/1000 of an {@link #Amp}. Useful when dealing with low-current applications
* like LED drivers or low-power circuits.
*/
public static final Current Milliamp = Milliamps; // alias
public static final CurrentUnit Milliamp = Milliamps; // alias
// Energy
// EnergyUnit
/** The base unit of energy. */
public static final Energy Joules = BaseUnits.Energy;
public static final EnergyUnit Joules = BaseUnits.EnergyUnit;
/** The base unit of energy. */
public static final Energy Joule = Joules; // alias
public static final EnergyUnit Joule = Joules; // alias
/**
* A unit equal to 1/1000 of a {@link #Joule}. Useful when dealing with lower-power applications.
*/
public static final Energy Millijoules = Milli(Joules);
public static final EnergyUnit Millijoules = Milli(Joules);
/**
* A unit equal to 1/1000 of a {@link #Joule}. Useful when dealing with lower-power applications.
*/
public static final Energy Millijoule = Millijoules; // alias
public static final EnergyUnit Millijoule = Millijoules; // alias
/**
* A unit equal to 1,000 {@link #Joules}. Useful when dealing with higher-level robot energy
* usage.
*/
public static final Energy Kilojoules = Kilo(Joules);
public static final EnergyUnit Kilojoules = Kilo(Joules);
/**
* A unit equal to 1,000 {@link #Joules}. Useful when dealing with higher-level robot energy
* usage.
*/
public static final Energy Kilojoule = Kilojoules; // alias
public static final EnergyUnit Kilojoule = Kilojoules; // alias
// Power
// PowerUnit
/** The base unit of power. Equivalent to one {@link #Joule} per {@link #Second}. */
public static final Power Watts = BaseUnits.Power;
public static final PowerUnit Watts = derive(Joules.per(Second)).named("Watt").symbol("W").make();
/** The base unit of power. Equivalent to one {@link #Joule} per {@link #Second}. */
public static final Power Watt = Watts; // alias
public static final PowerUnit Watt = Watts; // alias
/**
* A unit equal to 1/1000 of a {@link #Watt}. Useful when dealing with lower-power applications.
*/
public static final Power Milliwatts = Milli(Watts);
public static final PowerUnit Milliwatts = Milli(Watts);
/**
* A unit equal to 1/1000 of a {@link #Watt}. Useful when dealing with lower-power applications.
*/
public static final Power Milliwatt = Milliwatts; // alias
public static final PowerUnit Milliwatt = Milliwatts; // alias
/**
* A unit equal to 745.7 {@link #Watts}. May be useful when dealing with high-power gearboxes and
* motors.
*/
public static final Power Horsepower =
public static final PowerUnit Horsepower =
derive(Watts).aggregate(745.7).named("Horsepower").symbol("HP").make();
// Temperature
// TemperatureUnit
/**
* The base unit of temperature, where a value of 0 corresponds with absolutely zero energy in the
* measured system. Not particularly useful for robots unless you're cooling motors with liquid
* helium.
*/
public static final Temperature Kelvin = BaseUnits.Temperature;
public static final TemperatureUnit Kelvin = BaseUnits.TemperatureUnit;
/**
* The base SI unit of temperature, where a value of 0 roughly corresponds to the freezing point
* of water and a value of 100 corresponds to the boiling point. Electronics tend to exhibit
* The standard SI unit of temperature, where a value of 0 roughly corresponds to the freezing
* point of water and a value of 100 corresponds to the boiling point. Electronics tend to exhibit
* degraded performance or damage above 90 degrees Celsius.
*/
public static final Temperature Celsius =
public static final TemperatureUnit Celsius =
derive(Kelvin).offset(+273.15).named("Celsius").symbol("°C").make();
/**
* The base imperial (American) unit of temperature, where a value of 32 roughly corresponds to
* the freezing point of water and a value of 212 corresponds to the boiling point.
*/
public static final Temperature Fahrenheit =
public static final TemperatureUnit Fahrenheit =
derive(Celsius)
.mappingInputRange(0, 100)
.toOutputRange(32, 212)
@@ -386,28 +499,28 @@ public final class Units {
* A standard unit for measuring linear mechanisms' feedforward voltages based on a model of the
* system and a desired commanded linear velocity.
*/
public static final Per<Voltage, Velocity<Distance>> VoltsPerMeterPerSecond =
public static final PerUnit<VoltageUnit, LinearVelocityUnit> VoltsPerMeterPerSecond =
Volts.per(MetersPerSecond);
/**
* A standard unit for measuring linear mechanisms' feedforward voltages based on a model of the
* system and a desired commanded linear acceleration.
*/
public static final Per<Voltage, Velocity<Velocity<Distance>>> VoltsPerMeterPerSecondSquared =
public static final PerUnit<VoltageUnit, LinearAccelerationUnit> VoltsPerMeterPerSecondSquared =
Volts.per(MetersPerSecondPerSecond);
/**
* A standard unit for measuring angular mechanisms' feedforward voltages based on a model of the
* system and a desired commanded angular velocity.
*/
public static final Per<Voltage, Velocity<Angle>> VoltsPerRadianPerSecond =
public static final PerUnit<VoltageUnit, AngularVelocityUnit> VoltsPerRadianPerSecond =
Volts.per(RadiansPerSecond);
/**
* A standard unit for measuring angular mechanisms' feedforward voltages based on a model of the
* system and a desired commanded angular acceleration.
*/
public static final Per<Voltage, Velocity<Velocity<Angle>>> VoltsPerRadianPerSecondSquared =
public static final PerUnit<VoltageUnit, AngularAccelerationUnit> VoltsPerRadianPerSecondSquared =
Volts.per(RadiansPerSecond.per(Second));
/**
@@ -420,7 +533,7 @@ public final class Units {
* @return the milli-unit
*/
@SuppressWarnings("checkstyle:methodname")
public static <U extends Unit<U>> U Milli(Unit<U> baseUnit, String name, String symbol) {
public static <U extends Unit> U Milli(U baseUnit, String name, String symbol) {
return derive(baseUnit).splitInto(1000).named(name).symbol(symbol).make();
}
@@ -432,7 +545,7 @@ public final class Units {
* @return the milli-unit
*/
@SuppressWarnings("checkstyle:methodname")
public static <U extends Unit<U>> U Milli(Unit<U> baseUnit) {
public static <U extends Unit> U Milli(U baseUnit) {
return Milli(
baseUnit, "Milli" + baseUnit.name().toLowerCase(Locale.ROOT), "m" + baseUnit.symbol());
}
@@ -448,7 +561,7 @@ public final class Units {
* @return the micro-unit
*/
@SuppressWarnings("checkstyle:methodname")
public static <U extends Unit<U>> U Micro(Unit<U> baseUnit, String name, String symbol) {
public static <U extends Unit> U Micro(U baseUnit, String name, String symbol) {
return derive(baseUnit).splitInto(1_000_000).named(name).symbol(symbol).make();
}
@@ -460,7 +573,7 @@ public final class Units {
* @return the micro-unit
*/
@SuppressWarnings("checkstyle:methodname")
public static <U extends Unit<U>> U Micro(Unit<U> baseUnit) {
public static <U extends Unit> U Micro(U baseUnit) {
return Micro(
baseUnit, "Micro" + baseUnit.name().toLowerCase(Locale.ROOT), "u" + baseUnit.symbol());
}
@@ -475,7 +588,7 @@ public final class Units {
* @return the kilo-unit
*/
@SuppressWarnings("checkstyle:methodname")
public static <U extends Unit<U>> U Kilo(Unit<U> baseUnit, String name, String symbol) {
public static <U extends Unit> U Kilo(U baseUnit, String name, String symbol) {
return derive(baseUnit).aggregate(1000).named(name).symbol(symbol).make();
}
@@ -487,7 +600,7 @@ public final class Units {
* @return the kilo-unit
*/
@SuppressWarnings("checkstyle:methodname")
public static <U extends Unit<U>> U Kilo(Unit<U> baseUnit) {
public static <U extends Unit> U Kilo(U baseUnit) {
return Kilo(
baseUnit, "Kilo" + baseUnit.name().toLowerCase(Locale.ROOT), "K" + baseUnit.symbol());
}
@@ -500,8 +613,7 @@ public final class Units {
* @param <U> the dimension of the unit to derive
* @return a builder object
*/
@SuppressWarnings("unchecked")
public static <U extends Unit<U>> UnitBuilder<U> derive(Unit<U> unit) {
return new UnitBuilder<>((U) unit);
public static <U extends Unit> UnitBuilder<U> derive(U unit) {
return new UnitBuilder<>(unit);
}
}

View File

@@ -1,188 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
import edu.wpi.first.units.collections.LongToObjectHashMap;
import java.util.Objects;
/**
* Unit of velocity dimension that is a combination of a distance unit (numerator) and a time unit
* (denominator).
*
* <p>This is the base type for units of velocity dimension. It is also used in combination with a
* distance dimension to specify the dimension for {@link Measure}. For example: <code>
* Measure&lt;Velocity&lt;Distance&gt;&gt;</code>.
*
* <p>Actual units (such as {@link Units#MetersPerSecond} and {@link Units#RPM}) can be found in the
* {@link Units} class.
*
* @param <D> the distance unit, such as {@link Angle} or {@link Distance}
*/
public class Velocity<D extends Unit<D>> extends Unit<Velocity<D>> {
private final D m_unit;
private final Time m_period;
/**
* Stores velocity units that were created ad-hoc using {@link #combine(Unit, Time, String,
* String)}. Does not store objects created directly by constructors.
*/
@SuppressWarnings("rawtypes")
private static final LongToObjectHashMap<Velocity> cache = new LongToObjectHashMap<>();
/** Generates a cache key used for cache lookups. */
private static long cacheKey(Unit<?> numerator, Unit<?> denominator) {
return ((long) numerator.hashCode()) << 32L | (denominator.hashCode() & 0xFFFFFFFFL);
}
/**
* Creates a new velocity unit derived from an arbitrary numerator and time period units.
*
* <p>Results of this method are cached so future invocations with the same arguments will return
* the pre-existing units instead of generating new identical ones.
*
* <pre>
* Velocity.combine(Kilograms, Second) // mass flow
* Velocity.combine(Feet, Millisecond) // linear speed
* Velocity.combine(Radians, Second) // angular speed
*
* Velocity.combine(Feet.per(Second), Second) // linear acceleration in ft/s/s
* Velocity.combine(Radians.per(Second), Second) // angular acceleration
* </pre>
*
* <p>It's recommended to use the convenience function {@link Unit#per(Time)} instead of calling
* this factory directly.
*
* @param <D> the type of the numerator unit
* @param numerator the numerator unit
* @param period the period for unit time
* @param name the name of the new velocity unit
* @param symbol the symbol of the new velocity unit
* @return the new unit
*/
@SuppressWarnings("unchecked")
public static <D extends Unit<D>> Velocity<D> combine(
Unit<D> numerator, Time period, String name, String symbol) {
long key = cacheKey(numerator, period);
if (cache.containsKey(key)) {
return cache.get(key);
}
Velocity<D> velocity = new Velocity<>((D) numerator, period, name, symbol);
cache.put(key, velocity);
return velocity;
}
/**
* Creates a new velocity unit derived from an arbitrary numerator and time period units.
*
* <p>Results of this method are cached so future invocations with the same arguments will return
* the pre-existing units instead of generating new identical ones.
*
* <p>This method automatically generates a new name and symbol for the new velocity unit.
*
* <pre>
* Velocity.combine(Kilograms, Second) // mass flow
* Velocity.combine(Feet, Millisecond) // linear speed
* Velocity.combine(Radians, Second) // angular speed
*
* Velocity.combine(Feet.per(Second), Second) // linear acceleration in ft/s/s
* Velocity.combine(Radians.per(Second), Second) // angular acceleration
* </pre>
*
* <p>It's recommended to use the convenience function {@link Unit#per(Time)} instead of calling
* this factory directly.
*
* @param <D> the type of the numerator unit
* @param numerator the numerator unit
* @param period the period for unit time
* @return the new unit
*/
@SuppressWarnings("unchecked")
public static <D extends Unit<D>> Velocity<D> combine(Unit<D> numerator, Time period) {
long key = cacheKey(numerator, period);
if (cache.containsKey(key)) {
return cache.get(key);
}
var name = numerator.name() + " per " + period.name();
var symbol = numerator.symbol() + "/" + period.symbol();
Velocity<D> velocity = new Velocity<>((D) numerator, period, name, symbol);
cache.put(key, velocity);
return velocity;
}
@SuppressWarnings({"unchecked", "rawtypes"})
Velocity(D unit, Time period, String name, String symbol) {
super(
unit.isBaseUnit() && period.isBaseUnit()
? null
: combine(unit.getBaseUnit(), period.getBaseUnit()),
unit.toBaseUnits(1) / period.toBaseUnits(1),
name,
symbol);
this.m_unit = unit;
this.m_period = period;
}
@SuppressWarnings({"unchecked", "rawtypes"})
Velocity(
Velocity<D> baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
this.m_unit = baseUnit.getUnit();
this.m_period = baseUnit.getPeriod();
}
/**
* Gets the major unit being measured (eg Meters for Meters per Second).
*
* @return the major unit
*/
public D getUnit() {
return m_unit;
}
/**
* Gets the period unit of the velocity, eg Seconds or Milliseconds.
*
* @return the period unit
*/
public Time getPeriod() {
return m_period;
}
/**
* Returns the reciprocal of this velocity.
*
* @return the reciprocal
*/
public Per<Time, D> reciprocal() {
return m_period.per(m_unit);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!super.equals(o)) {
return false;
}
Velocity<?> velocity = (Velocity<?>) o;
return m_unit.equals(velocity.m_unit) && m_period.equals(velocity.m_period);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), m_unit, m_period);
}
}

View File

@@ -0,0 +1,140 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
import edu.wpi.first.units.measure.ImmutableVelocity;
import edu.wpi.first.units.measure.MutVelocity;
import edu.wpi.first.units.measure.Velocity;
/**
* Unit of velocity dimension that is a combination of a distance unit (numerator) and a time unit
* (denominator).
*
* <p>This is a generic velocity type for units that do not have discrete velocity units (eg {@link
* DistanceUnit} has {@link LinearVelocityUnit}, and so would not use this class).
*
* @param <D> the unit of the changing quantity, such as {@link VoltageUnit} or {@link
* TemperatureUnit}
*/
public final class VelocityUnit<D extends Unit> extends PerUnit<D, TimeUnit> {
@SuppressWarnings("rawtypes")
private static final CombinatoryUnitCache<Unit, TimeUnit, VelocityUnit> cache =
new CombinatoryUnitCache<>(VelocityUnit::new);
@SuppressWarnings("unchecked")
VelocityUnit(D numerator, TimeUnit denominator) {
super(
numerator.isBaseUnit() && denominator.isBaseUnit()
? null
: combine((D) numerator.getBaseUnit(), denominator.getBaseUnit()),
numerator,
denominator);
}
VelocityUnit(
VelocityUnit<D> baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
/**
* Combines a dimension unit and a unit of the period of change to create a unit of velocity.
*
* @param unit the unit of the changing dimension
* @param period the unit of the period of change in the velocity
* @param <D> the unit of the changing dimension
* @return the combined velocity unit
*/
@SuppressWarnings("unchecked")
public static <D extends Unit> VelocityUnit<D> combine(D unit, TimeUnit period) {
return cache.combine(unit, period);
}
@Override
public VelocityUnit<D> getBaseUnit() {
return (VelocityUnit<D>) super.getBaseUnit();
}
/**
* Gets the major unit being measured (eg Meters for Meters per Second).
*
* @return the major unit
*/
public D getUnit() {
return numerator();
}
/**
* Gets the period unit of the velocity, eg Seconds or Milliseconds.
*
* @return the period unit
*/
public TimeUnit getPeriod() {
return denominator();
}
@Override
public Velocity<D> of(double magnitude) {
return new ImmutableVelocity<>(magnitude, toBaseUnits(magnitude), this);
}
@Override
public Velocity<D> ofBaseUnits(double baseUnitMagnitude) {
return new ImmutableVelocity<>(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
@SuppressWarnings("unchecked")
public Measure<? extends VelocityUnit<D>> zero() {
return (Measure<? extends VelocityUnit<D>>) super.zero();
}
@Override
@SuppressWarnings("unchecked")
public Measure<? extends VelocityUnit<D>> one() {
return (Measure<? extends VelocityUnit<D>>) super.one();
}
@Override
public MutableMeasure<VelocityUnit<D>, ?, ?> mutable(double initialMagnitude) {
return new MutVelocity<>(initialMagnitude, toBaseUnits(initialMagnitude), this);
}
/**
* Combines this velocity unit with a unit of a period of change to create an acceleration unit.
*
* @param period the unit of the period of change
* @return the acceleration unit
*/
@Override
public AccelerationUnit<D> per(TimeUnit period) {
return AccelerationUnit.combine(this, period);
}
/**
* Creates a ratio unit between this unit and an arbitrary other unit.
*
* @param other the other unit
* @param <U> the type of the other unit
* @return the ratio unit
*/
public <U extends Unit> PerUnit<VelocityUnit<D>, U> per(U other) {
return PerUnit.combine(this, other);
}
/**
* Converts a measurement value in terms of another velocity unit to this unit.
*
* @param magnitude the magnitude of the measurement in terms of the other velocity unit
* @param otherUnit the other velocity unit
* @return the value of the measurement in terms of this unit
*/
public double convertFrom(double magnitude, VelocityUnit<? extends D> otherUnit) {
return fromBaseUnits(otherUnit.toBaseUnits(magnitude));
}
}

View File

@@ -1,46 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
import static edu.wpi.first.units.Units.Watts;
/**
* Unit of electric voltage dimension.
*
* <p>This is the base type for units of voltage dimension. It is also used to specify the dimension
* for {@link Measure}: <code>Measure&lt;Voltage&gt;</code>.
*
* <p>Actual units (such as {@link Units#Volts} and {@link Units#Millivolts}) can be found in the
* {@link Units} class.
*/
public class Voltage extends Unit<Voltage> {
Voltage(Voltage baseUnit, double baseUnitEquivalent, String name, String symbol) {
super(baseUnit, baseUnitEquivalent, name, symbol);
}
Voltage(
Voltage baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
/**
* Constructs a unit of power equivalent to this unit of voltage multiplied by another unit of
* electrical current. For example, {@code Volts.times(Amps)} will return a unit of power
* equivalent to one Watt; {@code Volts.times(Milliams)} will return a unit of power equivalent to
* a milliwatt, and so on.
*
* @param current the current unit to multiply by
* @param name the name of the resulting unit of power
* @param symbol the symbol used to represent the unit of power
* @return the power unit
*/
public Power times(Unit<Current> current, String name, String symbol) {
return new Power(Watts, toBaseUnits(1) * current.toBaseUnits(1), name, symbol);
}
}

View File

@@ -0,0 +1,105 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units;
import edu.wpi.first.units.measure.ImmutableVoltage;
import edu.wpi.first.units.measure.MutVoltage;
import edu.wpi.first.units.measure.Voltage;
/**
* Unit of electric voltage dimension.
*
* <p>This is the base type for units of voltage dimension. It is also used to specify the dimension
* for {@link Measure}: <code>Measure&lt;VoltageUnit&gt;</code>.
*
* <p>Actual units (such as {@link Units#Volts} and {@link Units#Millivolts}) can be found in the
* {@link Units} class.
*/
public final class VoltageUnit extends Unit {
VoltageUnit(VoltageUnit baseUnit, double baseUnitEquivalent, String name, String symbol) {
super(baseUnit, baseUnitEquivalent, name, symbol);
}
VoltageUnit(
VoltageUnit baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
@Override
public VoltageUnit getBaseUnit() {
return (VoltageUnit) super.getBaseUnit();
}
/**
* Constructs a unit of power equivalent to this unit of voltage multiplied by another unit of
* electrical current. For example, {@code Volts.times(Amps)} will return a unit of power
* equivalent to one Watt; {@code Volts.times(Milliamps)} will return a unit of power equivalent
* to a milliwatt, and so on.
*
* @param current the current unit to multiply by
* @param name the name of the resulting unit of power
* @param symbol the symbol used to represent the unit of power
* @return the power unit
*/
public PowerUnit mult(CurrentUnit current, String name, String symbol) {
return Units.derive(PowerUnit.combine(this, current)).named(name).symbol(symbol).make();
}
@Override
public Voltage of(double magnitude) {
return new ImmutableVoltage(magnitude, toBaseUnits(magnitude), this);
}
@Override
public Voltage ofBaseUnits(double baseUnitMagnitude) {
return new ImmutableVoltage(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public Voltage zero() {
return (Voltage) super.zero();
}
@Override
public Voltage one() {
return (Voltage) super.one();
}
@Override
public MutVoltage mutable(double magnitude) {
return new MutVoltage(magnitude, toBaseUnits(magnitude), this);
}
@Override
public VelocityUnit<VoltageUnit> per(TimeUnit period) {
return VelocityUnit.combine(this, period);
}
/**
* Creates a generic ratio unit of this voltage to a different unit type.
*
* @param other the other unit type
* @param <U> the type of the other unit
* @return the combined ratio type
*/
public <U extends Unit> PerUnit<VoltageUnit, U> per(U other) {
return PerUnit.combine(this, other);
}
/**
* Converts a measurement value in terms of another voltage unit to this unit.
*
* @param magnitude the magnitude of the measurement in terms of the other voltage unit
* @param otherUnit the other voltage unit
* @return the value of the measurement in terms of this unit
*/
public double convertFrom(double magnitude, VoltageUnit otherUnit) {
return fromBaseUnits(otherUnit.toBaseUnits(magnitude));
}
}

View File

@@ -0,0 +1,79 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units.mutable;
import edu.wpi.first.units.ImmutableMeasure;
import edu.wpi.first.units.Measure;
import edu.wpi.first.units.MutableMeasure;
import edu.wpi.first.units.Unit;
import edu.wpi.first.units.measure.Dimensionless;
/**
* A generic implementation of a mutable measure. This is used in scenarios no unit-specific mutable
* implementation can be determined.
*
* @param <U> the unit of measure
*/
public final class GenericMutableMeasureImpl<U extends Unit>
extends MutableMeasureBase<U, Measure<U>, GenericMutableMeasureImpl<U>> {
/**
* Initializes the mutable measure with initial conditions. Both relative and base unit magnitudes
* are required to avoid unnecessary calculations. It is up to the caller to ensure they are
* correct.
*
* @param initialValue the initial magnitude of the measure, in terms of the unit
* @param baseUnitMagnitude the initial magnitude of the measure, in terms of the base unit
* @param unit the initial unit of measure
*/
public GenericMutableMeasureImpl(double initialValue, double baseUnitMagnitude, U unit) {
super(initialValue, baseUnitMagnitude, unit);
}
@Override
public Measure<U> copy() {
return ImmutableMeasure.ofBaseUnits(m_baseUnitMagnitude, m_unit);
}
@Override
public MutableMeasure<U, ?, ?> mutableCopy() {
return new GenericMutableMeasureImpl<>(m_magnitude, m_baseUnitMagnitude, m_unit);
}
@Override
public Measure<U> unaryMinus() {
return ImmutableMeasure.ofBaseUnits(0 - m_baseUnitMagnitude, m_unit);
}
@Override
public Measure<U> plus(Measure<? extends U> other) {
return ImmutableMeasure.ofBaseUnits(m_baseUnitMagnitude + other.baseUnitMagnitude(), m_unit);
}
@Override
public Measure<U> minus(Measure<? extends U> other) {
return ImmutableMeasure.ofBaseUnits(m_baseUnitMagnitude - other.baseUnitMagnitude(), m_unit);
}
@Override
public Measure<U> times(double multiplier) {
return ImmutableMeasure.ofBaseUnits(m_baseUnitMagnitude * multiplier, m_unit);
}
@Override
public Measure<U> times(Dimensionless multiplier) {
return ImmutableMeasure.ofBaseUnits(
m_baseUnitMagnitude * multiplier.baseUnitMagnitude(), m_unit);
}
@Override
public Measure<U> divide(double divisor) {
return ImmutableMeasure.ofBaseUnits(m_baseUnitMagnitude / divisor, m_unit);
}
@Override
public Measure<U> divide(Dimensionless divisor) {
return ImmutableMeasure.ofBaseUnits(m_baseUnitMagnitude / divisor.baseUnitMagnitude(), m_unit);
}
}

View File

@@ -0,0 +1,86 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.units.mutable;
import edu.wpi.first.units.Measure;
import edu.wpi.first.units.MutableMeasure;
import edu.wpi.first.units.Unit;
import java.util.Objects;
/**
* A partial implementation of {@link MutableMeasure} to handle most of the state and Java object-
* related implementations.
*
* @param <U> The dimension of measurement.
* @param <Base> The base measure type.
* @param <MutSelf> The self type. This MUST inherit from the base measure type.
*/
public abstract class MutableMeasureBase<
U extends Unit, Base extends Measure<U>, MutSelf extends MutableMeasure<U, Base, MutSelf>>
implements Measure<U>, MutableMeasure<U, Base, MutSelf> {
/** The magnitude of the measurement, in terms of {@link #m_unit}. */
protected double m_magnitude;
/** The magnitude of the measurement, in terms of {@link #m_unit}'s base unit. */
protected double m_baseUnitMagnitude;
/** The unit of measurement. */
protected U m_unit;
/**
* Initializes the mutable measure with initial conditions. Both relative and base unit magnitudes
* are required to avoid unnecessary calculations. It is up to the caller to ensure they are
* correct.
*
* @param magnitude the initial magnitude of the measure, in terms of the unit
* @param baseUnitMagnitude the initial magnitude of the measure, in terms of the base unit
* @param unit the initial unit of measure
*/
protected MutableMeasureBase(double magnitude, double baseUnitMagnitude, U unit) {
this.m_magnitude = magnitude;
this.m_baseUnitMagnitude = baseUnitMagnitude;
this.m_unit = Objects.requireNonNull(unit, "Unit cannot be null");
}
@Override
public double magnitude() {
return m_magnitude;
}
@Override
public double baseUnitMagnitude() {
return m_baseUnitMagnitude;
}
@Override
public U unit() {
return m_unit;
}
@Override
public String toString() {
return toShortString();
}
@Override
public boolean equals(Object o) {
return this == o || o instanceof Measure<?> m && isEquivalent(m);
}
@Override
public int hashCode() {
return Objects.hash(m_magnitude, m_baseUnitMagnitude, m_unit);
}
@Override
@SuppressWarnings("unchecked")
public MutSelf mut_replace(double magnitude, U newUnit) {
this.m_unit = Objects.requireNonNull(newUnit, "New unit cannot be null");
this.m_magnitude = magnitude;
this.m_baseUnitMagnitude = m_unit.toBaseUnits(magnitude);
return (MutSelf) this;
}
}