SCRIPT Move java files

This commit is contained in:
PJ Reiniger
2025-11-07 19:55:40 -05:00
committed by Peter Johnson
parent 7ca1be9bae
commit c350c5f112
1486 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,106 @@
// 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;
/**
* 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 Acceleration<>(magnitude, toBaseUnits(magnitude), this);
}
@Override
public Acceleration<D> ofBaseUnits(double baseUnitMagnitude) {
return new Acceleration<>(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 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

@@ -0,0 +1,87 @@
// 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;
/**
* 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 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,94 @@
// 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;
/** 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 AngularAcceleration(magnitude, toBaseUnits(magnitude), this);
}
@Override
public AngularAcceleration ofBaseUnits(double baseUnitMagnitude) {
return new AngularAcceleration(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public AngularAcceleration zero() {
return (AngularAcceleration) super.zero();
}
@Override
public AngularAcceleration one() {
return (AngularAcceleration) super.one();
}
@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,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.AngularMomentum;
/**
* 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 AngularMomentum(magnitude, toBaseUnits(magnitude), this);
}
@Override
public AngularMomentum ofBaseUnits(double baseUnitMagnitude) {
return new AngularMomentum(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public AngularMomentum zero() {
return (AngularMomentum) super.zero();
}
@Override
public AngularMomentum one() {
return (AngularMomentum) super.one();
}
@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,94 @@
// 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;
/** 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 AngularVelocity(magnitude, toBaseUnits(magnitude), this);
}
@Override
public AngularVelocity ofBaseUnits(double baseUnitMagnitude) {
return new AngularVelocity(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public AngularVelocity zero() {
return (AngularVelocity) super.zero();
}
@Override
public AngularVelocity one() {
return (AngularVelocity) super.one();
}
@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

@@ -0,0 +1,40 @@
// 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;
/** The base units of measure. */
public final class BaseUnits {
private BaseUnits() {
// Prevent instantiation
}
/** The standard unit of distance, meters. */
public static final DistanceUnit DistanceUnit = new DistanceUnit(null, 1, "Meter", "m");
/** The standard unit of time, seconds. */
public static final TimeUnit TimeUnit = new TimeUnit(null, 1, "Second", "s");
/** The standard unit of mass, kilograms. */
public static final MassUnit MassUnit = new MassUnit(null, 1, "Kilogram", "Kg");
/** The standard unit of angles, radians. */
public static final AngleUnit AngleUnit = new AngleUnit(null, 1, "Radian", "rad");
/** The standard "unitless" unit. */
public static final DimensionlessUnit Value = new DimensionlessUnit(null, 1, "<?>", "<?>");
/** The standard unit of voltage, volts. */
public static final VoltageUnit VoltageUnit = new VoltageUnit(null, 1, "Volt", "V");
/** The standard unit of electric current, amperes. */
public static final CurrentUnit CurrentUnit = new CurrentUnit(null, 1, "Amp", "A");
/** The standard unit of energy, joules. */
public static final EnergyUnit EnergyUnit = new EnergyUnit(null, 1, "Joule", "J");
/** The standard unit of temperature, kelvin. */
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

@@ -0,0 +1,98 @@
// 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;
/**
* 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 Current(magnitude, toBaseUnits(magnitude), this);
}
@Override
public Current ofBaseUnits(double baseUnitMagnitude) {
return new Current(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public Current zero() {
return (Current) super.zero();
}
@Override
public Current one() {
return (Current) super.one();
}
@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

@@ -0,0 +1,92 @@
// 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;
/**
* 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 Dimensionless(magnitude, toBaseUnits(magnitude), this);
}
@Override
public Dimensionless ofBaseUnits(double baseUnitMagnitude) {
return new Dimensionless(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public Dimensionless zero() {
return (Dimensionless) super.zero();
}
@Override
public Dimensionless one() {
return (Dimensionless) super.one();
}
/**
* 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

@@ -0,0 +1,95 @@
// 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;
/**
* 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 Distance(magnitude, toBaseUnits(magnitude), this);
}
@Override
public Distance ofBaseUnits(double baseUnitMagnitude) {
return new Distance(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public Distance zero() {
return (Distance) super.zero();
}
@Override
public Distance one() {
return (Distance) super.one();
}
/**
* 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

@@ -0,0 +1,89 @@
// 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;
/**
* 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 Energy(magnitude, toBaseUnits(magnitude), this);
}
@Override
public Energy ofBaseUnits(double baseUnitMagnitude) {
return new Energy(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public Energy zero() {
return (Energy) super.zero();
}
@Override
public Energy one() {
return (Energy) super.one();
}
}

View File

@@ -0,0 +1,106 @@
// 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;
/** 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 Force(magnitude, toBaseUnits(magnitude), this);
}
@Override
public Force ofBaseUnits(double baseUnitMagnitude) {
return new Force(toBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public Force zero() {
return (Force) super.zero();
}
@Override
public Force one() {
return (Force) super.one();
}
@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,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 static edu.wpi.first.units.Units.Value;
import edu.wpi.first.units.measure.Frequency;
/** 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 Frequency(magnitude, toBaseUnits(magnitude), this);
}
@Override
public Frequency ofBaseUnits(double baseUnitMagnitude) {
return new Frequency(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public Frequency zero() {
return (Frequency) super.zero();
}
@Override
public Frequency one() {
return (Frequency) super.one();
}
@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

@@ -0,0 +1,81 @@
// 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;
/**
* A measure holds the magnitude and unit of some dimension, such as distance, time, or speed. An
* immutable measure is <i>immutable</i> and <i>type safe</i>, making it easy to use in concurrent
* 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 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.
*
* @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 measure
*/
public static <U extends Unit> ImmutableMeasure<U> ofBaseUnits(double baseUnitMagnitude, U unit) {
return new ImmutableMeasure<>(unit.fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, unit);
}
/**
* Creates a new 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 measure
*/
public static <U extends Unit> ImmutableMeasure<U> ofRelativeUnits(
double relativeMagnitude, U unit) {
return new ImmutableMeasure<>(relativeMagnitude, unit.toBaseUnits(relativeMagnitude), 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> div(double divisor) {
return ofBaseUnits(baseUnitMagnitude / divisor, unit);
}
@Override
public Measure<U> div(Dimensionless divisor) {
return ofBaseUnits(baseUnitMagnitude / divisor.baseUnitMagnitude(), unit);
}
}

View File

@@ -0,0 +1,117 @@
// 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.LinearAcceleration;
/**
* 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 LinearAcceleration(magnitude, toBaseUnits(magnitude), this);
}
@Override
public LinearAcceleration ofBaseUnits(double baseUnitMagnitude) {
return new LinearAcceleration(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public LinearAcceleration zero() {
return (LinearAcceleration) super.zero();
}
@Override
public LinearAcceleration one() {
return (LinearAcceleration) super.one();
}
@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,104 @@
// 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.LinearMomentum;
/** 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 LinearMomentum(magnitude, toBaseUnits(magnitude), this);
}
@Override
public LinearMomentum ofBaseUnits(double baseUnitMagnitude) {
return new LinearMomentum(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public LinearMomentum zero() {
return (LinearMomentum) super.zero();
}
@Override
public LinearMomentum one() {
return (LinearMomentum) super.one();
}
@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,100 @@
// 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.LinearVelocity;
/** 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 LinearVelocity(magnitude, toBaseUnits(magnitude), this);
}
@Override
public LinearVelocity ofBaseUnits(double baseUnitMagnitude) {
return new LinearVelocity(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public LinearVelocity zero() {
return (LinearVelocity) super.zero();
}
@Override
public LinearVelocity one() {
return (LinearVelocity) super.one();
}
/**
* 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

@@ -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.Mass;
/**
* 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 Mass(magnitude, toBaseUnits(magnitude), this);
}
@Override
public Mass ofBaseUnits(double baseUnitMagnitude) {
return new Mass(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public Mass zero() {
return (Mass) super.zero();
}
@Override
public Mass one() {
return (Mass) super.one();
}
@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,100 @@
// 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.MomentOfInertia;
/**
* 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(
MomentOfInertiaUnit 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 MomentOfInertia(magnitude, toBaseUnits(magnitude), this);
}
@Override
public MomentOfInertia ofBaseUnits(double baseUnitMagnitude) {
return new MomentOfInertia(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public MomentOfInertia zero() {
return (MomentOfInertia) super.zero();
}
@Override
public MomentOfInertia one() {
return (MomentOfInertia) super.one();
}
@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

@@ -0,0 +1,222 @@
// 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.Mult;
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 Mult<>(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 Mult<>(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 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

@@ -0,0 +1,259 @@
// 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.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 Per<>(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 Per<>(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();
}
@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

@@ -0,0 +1,157 @@
// 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.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 Power(magnitude, toBaseUnits(magnitude), this);
}
@Override
public Power ofBaseUnits(double baseUnitMagnitude) {
return new Power(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public Power zero() {
return (Power) super.zero();
}
@Override
public Power one() {
return (Power) super.one();
}
@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

@@ -0,0 +1,97 @@
// 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.Resistance;
/**
* Unit of resistance dimension.
*
* <p>This is the base type for units of resistance dimension. It is also used to specify the
* dimension for {@link Measure}: <code>Measure&lt;ResistanceUnit&gt;</code>.
*
* <p>Actual units (such as {@link Units#Ohms} and {@link Units#KiloOhms}) can be found in the
* {@link Units} class.
*/
public final class ResistanceUnit extends PerUnit<VoltageUnit, CurrentUnit> {
private static final CombinatoryUnitCache<VoltageUnit, CurrentUnit, ResistanceUnit> cache =
new CombinatoryUnitCache<>(ResistanceUnit::new);
ResistanceUnit(VoltageUnit numerator, CurrentUnit denominator) {
super(
numerator.isBaseUnit() && denominator.isBaseUnit()
? null
: combine(numerator.getBaseUnit(), denominator.getBaseUnit()),
numerator,
denominator);
}
ResistanceUnit(
ResistanceUnit baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
}
/**
* Combines an voltage and a current unit to form a unit of resistance.
*
* @param voltage the unit of voltage
* @param current the unit of current
* @return the combined unit of resistance
*/
public static ResistanceUnit combine(VoltageUnit voltage, CurrentUnit current) {
return cache.combine(voltage, current);
}
@Override
public ResistanceUnit getBaseUnit() {
return (ResistanceUnit) super.getBaseUnit();
}
@Override
public Resistance of(double magnitude) {
return new Resistance(magnitude, toBaseUnits(magnitude), this);
}
@Override
public Resistance ofBaseUnits(double baseUnitMagnitude) {
return new Resistance(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public Resistance zero() {
return (Resistance) super.zero();
}
@Override
public Resistance one() {
return (Resistance) super.one();
}
/**
* 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<ResistanceUnit, 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, ResistanceUnit 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;
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 Temperature(magnitude, toBaseUnits(magnitude), this);
}
@Override
public Temperature ofBaseUnits(double baseUnitMagnitude) {
return new Temperature(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public Temperature zero() {
return (Temperature) super.zero();
}
@Override
public Temperature one() {
return (Temperature) super.one();
}
@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

@@ -0,0 +1,95 @@
// 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.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 Time(magnitude, toBaseUnits(magnitude), this);
}
@Override
public Time ofBaseUnits(double baseUnitMagnitude) {
return new Time(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public Time zero() {
return (Time) super.zero();
}
@Override
public Time one() {
return (Time) super.one();
}
}

View File

@@ -0,0 +1,94 @@
// 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.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 Torque(magnitude, toBaseUnits(magnitude), this);
}
@Override
public Torque ofBaseUnits(double baseUnitMagnitude) {
return new Torque(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public Torque zero() {
return (Torque) super.zero();
}
@Override
public Torque one() {
return (Torque) super.one();
}
@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

@@ -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 java.util.Objects;
/**
* A function that accepts a single {@code double} and returns a {@code double} result. This is used
* to represent arbitrary mapping functions for converting units to and from a base unit
* representation. Temperature units, in particular, typically have an offset from a value in Kelvin
* and may have a multiplication factor added in, which means that units cannot always be
* represented as simple ratios of their base units.
*/
@FunctionalInterface
public interface UnaryFunction {
/** The identity function that simply returns the input value. */
UnaryFunction IDENTITY = x -> x;
/**
* Applies this function to the input value and returns the result.
*
* @param input the input value to the function
* @return the result
*/
double apply(double input);
/**
* Constructs a new function that first calls this function, then passes the result to another as
* input.
*
* <pre>
* f = x -&gt; x + 1 // f(x) = x + 1
* g = x -&gt; 2 * x // g(x) = 2x
*
* h = f.pipeTo(g) // h(x) = g(f(x))
* </pre>
*
* @param next the next operation to pipe to
* @return the composite function g(f(x))
*/
default UnaryFunction pipeTo(UnaryFunction next) {
Objects.requireNonNull(next, "The next operation in the chain must be provided");
return x -> next.apply(this.apply(x));
}
/**
* Creates a composite function h(x) such that h(x) = f(x) * g(x).
*
* @param multiplier the function to multiply this one by
* @return the composite function f(x) * g(x)
*/
default UnaryFunction mult(UnaryFunction multiplier) {
Objects.requireNonNull(multiplier, "A multiplier function must be provided");
return x -> this.apply(x) * multiplier.apply(x);
}
/**
* Creates a composite function h(x) such that h(x) = k * f(x).
*
* @param multiplier the constant value to multiply this function's results by
* @return the composite function k * f(x)
*/
default UnaryFunction mult(double multiplier) {
return x -> this.apply(x) * multiplier;
}
/**
* Creates a composite function h(x) such that h(x) = f(x) / g(x).
*
* @param divisor the function to divide this one by
* @return the composite function f(x) / g(x)
*/
default UnaryFunction div(UnaryFunction divisor) {
Objects.requireNonNull(divisor, "A divisor function must be provided");
return x -> {
double numerator = this.apply(x);
// fast-track to avoid another function call
// avoids returning NaN if divisor is also zero
if (numerator == 0) {
return 0;
}
double div = divisor.apply(x);
return numerator / div; // NOTE: returns +Infinity or -Infinity if div is zero
};
}
/**
* Creates a composite function h(x) such that h(x) = 1/k * f(x).
*
* @param divisor the constant value to divide this function's results by
* @return the composite function 1/k * f(x)
*/
default UnaryFunction div(double divisor) {
return x -> this.apply(x) / divisor;
}
/**
* Creates a composite function h(x) such that h(x) = f(x) ^ g(x).
*
* @param exponent the function to exponentiate this function's results by
* @return the composite function f(x) ^ g(x)
*/
default UnaryFunction exp(UnaryFunction exponent) {
Objects.requireNonNull(exponent, "An exponent function must be provided");
return x -> Math.pow(this.apply(x), exponent.apply(x));
}
/**
* Creates a composite function h(x) such that h(x) = f(x) ^ k.
*
* @param exponent the constant value to exponentiate this function's results by
* @return the composite function f(x) ^ k
*/
default UnaryFunction exp(double exponent) {
return x -> Math.pow(this.apply(x), exponent);
}
}

View File

@@ -0,0 +1,251 @@
// 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 java.util.Objects;
/**
* Unit of measurement that defines a quantity, such as grams, meters, or seconds.
*
* <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.
*/
public abstract class Unit {
private final UnaryFunction m_toBaseConverter;
private final UnaryFunction m_fromBaseConverter;
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.
*
* @param baseUnit the base unit, e.g. Meters for distances. Set this to {@code null} if the unit
* being constructed is its own base unit
* @param toBaseConverter a function for converting units of this type to the base unit
* @param fromBaseConverter a function for converting units of the base unit to this one
* @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("this-escape")
protected Unit(
Unit baseUnit,
UnaryFunction toBaseConverter,
UnaryFunction fromBaseConverter,
String name,
String symbol) {
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);
}
/**
* Creates a new unit with the given name and multiplier to the base unit.
*
* @param baseUnit the base unit, e.g. Meters for distances
* @param baseUnitEquivalent the multiplier to convert this unit to the base unit of this type.
* For example, meters has a multiplier of 1, mm has a multiplier of 1e3, and km has
* multiplier of 1e-3.
* @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(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);
/**
* 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
*
* Unit derivedUnit = new Unit(baseUnit, ...);
* derivedUnit.getBaseUnit(); // returns baseUnit
* </code></pre>
*
* @return the base unit
*/
public Unit getBaseUnit() {
return m_baseUnit;
}
/**
* Checks if this unit is the base unit for its own system of measurement.
*
* @return true if this is the base unit, false if not
*/
public boolean isBaseUnit() {
return this.equals(m_baseUnit);
}
/**
* Converts a value in terms of base units to a value in terms of this unit.
*
* @param valueInBaseUnits the value in base units to convert
* @return the equivalent value in terms of this unit
*/
public double fromBaseUnits(double valueInBaseUnits) {
return m_fromBaseConverter.apply(valueInBaseUnits);
}
/**
* Converts a value in terms of this unit to a value in terms of the base unit.
*
* @param valueInNativeUnits the value in terms of this unit to convert
* @return the equivalent value in terms of the base unit
*/
public double toBaseUnits(double valueInNativeUnits) {
return m_toBaseConverter.apply(valueInNativeUnits);
}
/**
* 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.
*
* @return the conversion function
*/
public UnaryFunction getConverterToBase() {
return m_toBaseConverter;
}
/**
* Gets the conversion function used to convert values to terms of this unit. This generally
* shouldn't need to be used directly; prefer {@link #fromBaseUnits(double)} instead.
*
* @return the conversion function
*/
public UnaryFunction getConverterFromBase() {
return m_fromBaseConverter;
}
/**
* 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
* own units, to within {@link Measure#EQUIVALENCE_THRESHOLD}.
*
* @param other the unit to compare to.
* @return true if both units are equivalent, false if not
*/
public boolean equivalent(Unit other) {
if (!getClass().equals(other.getClass())) {
// different unit types, not compatible
return false;
}
double arbitrary = 16_777.214; // 2^24 / 1e3
return Math.abs(
this.m_fromBaseConverter.apply(arbitrary)
- other.m_fromBaseConverter.apply(arbitrary))
<= Measure.EQUIVALENCE_THRESHOLD
&& Math.abs(
this.m_toBaseConverter.apply(arbitrary) - other.m_toBaseConverter.apply(arbitrary))
<= Measure.EQUIVALENCE_THRESHOLD;
}
@Override
public boolean equals(Object o) {
return this == o
|| o instanceof Unit that
&& m_name.equals(that.m_name)
&& m_symbol.equals(that.m_symbol)
&& this.equivalent(that);
}
@Override
public int hashCode() {
return Objects.hash(m_toBaseConverter, m_fromBaseConverter, m_name, m_symbol);
}
/**
* Gets the name of this unit.
*
* @return the unit's name
*/
public String name() {
return m_name;
}
/**
* Gets the symbol of this unit.
*
* @return the unit's symbol
*/
public String symbol() {
return m_symbol;
}
@Override
public String toString() {
return name();
}
}

View File

@@ -0,0 +1,293 @@
// 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 java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Objects;
/**
* Builder used for easily deriving new units from existing ones. When deriving a new unit, the base
* unit class <strong>must</strong> redeclare the constructor {@link Unit#Unit(Unit, UnaryFunction,
* UnaryFunction, String, String) (U, UnaryFunction, UnaryFunction, String, String)}. The unit
* builder class will invoke this constructor automatically and build the new unit. Alternatively,
* new units can be derived by passing an explicit constructor function to {@link
* #make(UnitConstructorFunction)}.
*
* @param <U> the type of the unit
*/
public final class UnitBuilder<U extends Unit> {
private final U m_base;
private UnaryFunction m_fromBase = UnaryFunction.IDENTITY;
private UnaryFunction m_toBase = UnaryFunction.IDENTITY;
private String m_name;
private String m_symbol;
/**
* Creates a new unit builder object, building off of a base unit. The base unit does not have to
* be <i>the</i> base unit of its unit system; furlongs work just as well here as meters.
*
* @param base the unit to base the new unit off of
*/
public UnitBuilder(U base) {
this.m_base = Objects.requireNonNull(base, "Base unit cannot be null");
}
/**
* Sets the unit conversions based on a simple offset. The new unit will have its values equal to
* (base value - offset).
*
* @param offset the offset
* @return this builder
*/
public UnitBuilder<U> offset(double offset) {
m_toBase = derivedValue -> derivedValue + offset;
m_fromBase = baseValue -> baseValue - offset;
return this;
}
/**
* Maps a value {@code value} in the range {@code [inMin..inMax]} to an output in the range {@code
* [outMin..outMax]}. Inputs outside the bounds will be mapped correspondingly to outputs outside
* the output bounds. Inputs equal to {@code inMin} will be mapped to {@code outMin}, and inputs
* equal to {@code inMax} will similarly be mapped to {@code outMax}.
*
* @param value the value to map
* @param inMin the minimum input value (does not have to be absolute)
* @param inMax the maximum input value (does not have to be absolute)
* @param outMin the minimum output value (does not have to be absolute)
* @param outMax the maximum output value (does not have to be absolute)
* @return the mapped output
*/
// NOTE: This method lives here instead of in MappingBuilder because inner classes can't
// define static methods prior to Java 16.
private static double mapValue(
double value, double inMin, double inMax, double outMin, double outMax) {
return (value - inMin) * (outMax - outMin) / (inMax - inMin) + outMin;
}
/** Helper class used for safely chaining mapping builder calls. */
public final class MappingBuilder {
private final double m_minInput;
private final double m_maxInput;
private MappingBuilder(double minInput, double maxInput) {
this.m_minInput = minInput;
this.m_maxInput = maxInput;
}
/**
* Finalizes the mapping by defining the output range.
*
* @param minOutput the minimum output value (does not have to be absolute)
* @param maxOutput the maximum output value (does not have to be absolute)
* @return the unit builder, for continued chaining
*/
public UnitBuilder<U> toOutputRange(double minOutput, double maxOutput) {
UnitBuilder.this.m_fromBase = x -> mapValue(x, m_minInput, m_maxInput, minOutput, maxOutput);
UnitBuilder.this.m_toBase = y -> mapValue(y, minOutput, maxOutput, m_minInput, m_maxInput);
return UnitBuilder.this;
}
}
/**
* Defines a mapping for values within the given input range. This method call should be
* immediately followed by {@code .toOutputRange}, eg {@code mappingInputRange(1,
* 2).toOutputRange(3, 4)}, which will return the unit builder for continued chaining.
*
* @param minBase the minimum input value (does not have to be absolute)
* @param maxBase the maximum output value (does not have to be absolute)
* @return a builder object used to define the output range
*/
public MappingBuilder mappingInputRange(double minBase, double maxBase) {
return new MappingBuilder(minBase, maxBase);
}
/**
* Sets the conversion function to transform values in the base unit to values in the derived
* unit.
*
* @param fromBase the conversion function
* @return the unit builder, for continued chaining
*/
public UnitBuilder<U> fromBase(UnaryFunction fromBase) {
this.m_fromBase = Objects.requireNonNull(fromBase, "fromBase function cannot be null");
return this;
}
/**
* Sets the conversion function to transform values in the derived unit to values in the base
* unit.
*
* @param toBase the conversion function
* @return the unit builder, for continued chaining
*/
public UnitBuilder<U> toBase(UnaryFunction toBase) {
this.m_toBase = Objects.requireNonNull(toBase, "toBase function cannot be null");
return this;
}
/**
* Sets the name of the new unit.
*
* @param name the new name
* @return the unit builder, for continued chaining
*/
public UnitBuilder<U> named(String name) {
this.m_name = name;
return this;
}
/**
* Sets the symbol of the new unit.
*
* @param symbol the new symbol
* @return the unit builder, for continued chaining
*/
public UnitBuilder<U> symbol(String symbol) {
this.m_symbol = symbol;
return this;
}
/**
* Helper for defining units that are a scalar fraction of the base unit, such as centimeters
* being 1/100th of the base unit (meters). The fraction value is specified as the denominator of
* the fraction, so a centimeter definition would use {@code splitInto(100)} instead of {@code
* splitInto(1/100.0)}.
*
* @param fraction the denominator portion of the fraction of the base unit that a value of 1 in
* the derived unit corresponds to
* @return the unit builder, for continued chaining
*/
public UnitBuilder<U> splitInto(double fraction) {
if (fraction == 0) {
throw new IllegalArgumentException("Fraction must be nonzero");
}
return toBase(x -> x / fraction).fromBase(b -> b * fraction);
}
/**
* Helper for defining units that are a scalar multiple of the base unit, such as kilometers being
* 1000x of the base unit (meters).
*
* @param aggregation the magnitude required for a measure in the base unit to equal a magnitude
* of 1 in the derived unit
* @return the unit builder, for continued chaining
*/
public UnitBuilder<U> aggregate(double aggregation) {
if (aggregation == 0) {
throw new IllegalArgumentException("Aggregation amount must be nonzero");
}
return toBase(x -> x * aggregation).fromBase(b -> b / aggregation);
}
/**
* A functional interface for constructing new units without relying on reflection.
*
* @param <U> the type of the unit
*/
@FunctionalInterface
public interface UnitConstructorFunction<U extends Unit> {
/**
* Creates a new unit instance based on its relation to the base unit of measure.
*
* @param baseUnit the base unit of the unit system
* @param toBaseUnits a function that converts values of the new unit to equivalent values in
* terms of the base unit
* @param fromBaseUnits a function that converts values in the base unit to equivalent values in
* terms of the new unit
* @param name the name of the new unit
* @param symbol the shorthand symbol of the new unit
* @return a new unit
*/
U create(
U baseUnit,
UnaryFunction toBaseUnits,
UnaryFunction fromBaseUnits,
String name,
String symbol);
}
/**
* Creates the new unit based off of the builder methods called prior, passing them to a provided
* constructor function.
*
* @param constructor the function to use to create the new derived unit
* @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");
Objects.requireNonNull(m_name, "new unit name was not set");
Objects.requireNonNull(m_symbol, "new unit symbol was not set");
return constructor.create(
(U) m_base.getBaseUnit(),
m_toBase.pipeTo(m_base.getConverterToBase()),
m_base.getConverterFromBase().pipeTo(m_fromBase),
m_name,
m_symbol);
}
/**
* Creates the new unit based off of the builder methods called prior.
*
* @return the new derived unit
* @throws NullPointerException if the unit conversions, unit name, or unit symbol were not set
* @throws RuntimeException if the base unit does not define a constructor accepting the
* conversion functions, unit name, and unit symbol - in that order
*/
public U make() {
return make(
(baseUnit, toBaseUnits, fromBaseUnits, name, symbol) -> {
var baseClass = baseUnit.getClass();
try {
var ctor = getConstructor(baseUnit);
return ctor.newInstance(baseUnit, toBaseUnits, fromBaseUnits, name, symbol);
} catch (InstantiationException e) {
throw new RuntimeException("Could not instantiate class " + baseClass.getName(), e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Could not access constructor", e);
} catch (InvocationTargetException e) {
throw new RuntimeException(
"Constructing " + baseClass.getName() + " raised an exception", e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(
"No compatible constructor "
+ baseClass.getSimpleName()
+ "("
+ baseClass.getSimpleName()
+ ", UnaryFunction, UnaryFunction, String, String)",
e);
}
});
}
@SuppressWarnings({"unchecked", "PMD.AvoidAccessibilityAlteration"})
private static <U extends Unit> Constructor<? extends U> getConstructor(U baseUnit)
throws NoSuchMethodException {
var baseClass = baseUnit.getClass();
var ctor =
baseClass.getDeclaredConstructor(
baseClass, // baseUnit
UnaryFunction.class, // toBaseUnits
UnaryFunction.class, // fromBaseUnits
String.class, // name
String.class); // symbol
// need to flag the constructor as accessible so we can use private, package-private,
// and protected constructors
ctor.setAccessible(true);
return (Constructor<? extends U>) ctor;
}
}

View File

@@ -0,0 +1,644 @@
// 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 java.util.Locale;
/** Contains a set of predefined units. */
public final class Units {
private Units() {
// Prevent instantiation
}
// Pseudo-classes describing the more common units of measure.
// 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 DistanceUnit Meters = BaseUnits.DistanceUnit;
/** The base unit of distance. */
public static final DistanceUnit Meter = Meters; // alias
/** 1/1000 of a {@link #Meter}. */
public static final DistanceUnit Millimeters = Milli(Meters, "Millimeter", "mm");
/** 1/1000 of a {@link #Meter}. */
public static final DistanceUnit Millimeter = Millimeters; // alias
/** 1/100 of a {@link #Meter}. */
public static final DistanceUnit Centimeters =
derive(Meters).splitInto(100).named("Centimeter").symbol("cm").make();
/** 1/100 of a {@link #Meter}. */
public static final DistanceUnit Centimeter = Centimeters; // alias
/** 25.4/1000 of a {@link #Meter} and 1/12 of a {@link #Foot}. */
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 DistanceUnit Inch = Inches; // alias
/** 304.8/1000 of a {@link #Meter}, or 12 {@link #Inches}. */
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 DistanceUnit Foot = Feet; // alias
// TimeUnit
/** The base unit of time. */
public static final TimeUnit Seconds = BaseUnits.TimeUnit;
/** Alias for {@link #Seconds} to make combined unit definitions read more smoothly. */
public static final TimeUnit Second = Seconds; // singularized alias
/** 1/1000 of a {@link #Seconds Second}. */
public static final TimeUnit Milliseconds = Milli(Seconds);
/** Alias for {@link #Milliseconds} to make combined unit definitions read more smoothly. */
public static final TimeUnit Millisecond = Milliseconds; // singularized alias
/** 1/1,000,000 of a {@link #Seconds Second}. */
public static final TimeUnit Microseconds = Micro(Seconds);
/** Alias for {@link #Microseconds} to make combined unit definitions read more smoothly. */
public static final TimeUnit Microsecond = Microseconds; // singularized alias
/** 60 {@link #Seconds}. */
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 TimeUnit Minute = Minutes; // singularized alias
// AngleUnit
/**
* 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 AngleUnit Radians = BaseUnits.AngleUnit;
/**
* 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 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 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 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 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 AngleUnit Rotation = Rotations; // alias
/** 1/360 of a turn around a circle, or 1/57.3 {@link #Radians}. */
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 AngleUnit Degree = Degrees; // alias
// 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 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 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 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 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 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 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 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 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 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 LinearAccelerationUnit FeetPerSecondPerSecond = FeetPerSecond.per(Second);
/**
* A unit of linear acceleration equivalent to accelerating at a rate of one {@link #Inch Inch}
* per {@link #Second} every second.
*/
public static final LinearAccelerationUnit InchesPerSecondPerSecond = InchesPerSecond.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 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 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 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 LinearAccelerationUnit Gs =
derive(MetersPerSecondPerSecond).aggregate(9.80665).named("G").symbol("G").make();
// MassUnit
/** The standard SI unit of mass. */
public static final MassUnit Kilograms = BaseUnits.MassUnit;
/** The standard SI unit of mass. */
public static final MassUnit Kilogram = Kilograms; // alias
/** 1/1000 of a {@link #Kilogram}. */
public static final MassUnit Grams = Milli(Kilograms, "Gram", "g");
/** 1/1000 of a {@link #Kilogram}. */
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 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 MassUnit Pound = Pounds; // alias
/** 1/16 of a {@link #Pound}. */
public static final MassUnit Ounces =
derive(Pounds).splitInto(16).named("Ounce").symbol("oz.").make();
/** 1/16 of a {@link #Pound}. */
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 standard SI unit for moment of inertia. */
public static final MomentOfInertiaUnit KilogramSquareMeters =
KilogramMetersSquaredPerSecond.mult(RadiansPerSecond);
// VoltageUnit
/** The base unit of electric potential. */
public static final VoltageUnit Volts = BaseUnits.VoltageUnit;
/** The base unit of electric potential. */
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 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 VoltageUnit Millivolt = Millivolts; // alias
// CurrentUnit
/** The base unit of electrical current. */
public static final CurrentUnit Amps = BaseUnits.CurrentUnit;
/** The base unit of electrical current. */
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 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 CurrentUnit Milliamp = Milliamps; // alias
// ResistanceUnit
/** The base unit of resistance. Equivalent to one {@link #Volt} per {@link #Amp}. */
public static final ResistanceUnit Ohms = derive(Volts.per(Amp)).named("Ohm").symbol("Ω").make();
/** The base unit of resistance. Equivalent to one {@link #Volt} per {@link #Amp}. */
public static final ResistanceUnit Ohm = Ohms; // alias
/** A unit equal to 1,000 {@link #Ohms}. */
public static final ResistanceUnit KiloOhms = Kilo(Ohms);
/** A unit equal to 1,000 {@link #Ohms}. */
public static final ResistanceUnit KiloOhm = KiloOhms; // alias
/** A unit equal to 1/1000 of a {@link #Ohm}. */
public static final ResistanceUnit MilliOhms = Milli(Ohms);
/** A unit equal to 1/1000 of a {@link #Ohm}. */
public static final ResistanceUnit MilliOhm = MilliOhms; // alias
// EnergyUnit
/** The base unit of energy. */
public static final EnergyUnit Joules = BaseUnits.EnergyUnit;
/** The base unit of energy. */
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 EnergyUnit Millijoules = Milli(Joules);
/**
* A unit equal to 1/1000 of a {@link #Joule}. Useful when dealing with lower-power applications.
*/
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 EnergyUnit Kilojoules = Kilo(Joules);
/**
* A unit equal to 1,000 {@link #Joules}. Useful when dealing with higher-level robot energy
* usage.
*/
public static final EnergyUnit Kilojoule = Kilojoules; // alias
// PowerUnit
/** The base unit of power. Equivalent to one {@link #Joule} per {@link #Second}. */
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 PowerUnit Watt = Watts; // alias
/**
* A unit equal to 1/1000 of a {@link #Watt}. Useful when dealing with lower-power applications.
*/
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 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 PowerUnit Horsepower =
derive(Watts).aggregate(745.7).named("Horsepower").symbol("HP").make();
// 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 TemperatureUnit Kelvin = BaseUnits.TemperatureUnit;
/**
* 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 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 TemperatureUnit Fahrenheit =
derive(Celsius)
.mappingInputRange(0, 100)
.toOutputRange(32, 212)
.named("Fahrenheit")
.symbol("°F")
.make();
// Standard feedforward units for kV and kA.
// kS and kG are just volts, which is already defined earlier
/**
* 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 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 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 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 PerUnit<VoltageUnit, AngularAccelerationUnit> VoltsPerRadianPerSecondSquared =
Volts.per(RadiansPerSecond.per(Second));
/**
* Creates a unit equal to a thousandth of the base unit, eg Milliseconds = Milli(Units.Seconds).
*
* @param <U> the type of the unit
* @param baseUnit the unit being derived from. This does not have to be the base unit of measure
* @param name the name of the new derived unit
* @param symbol the symbol of the new derived unit
* @return the milli-unit
*/
@SuppressWarnings("checkstyle:methodname")
public static <U extends Unit> U Milli(U baseUnit, String name, String symbol) {
return derive(baseUnit).splitInto(1000).named(name).symbol(symbol).make();
}
/**
* Creates a unit equal to a thousandth of the base unit, eg Milliseconds = Milli(Units.Seconds).
*
* @param <U> the type of the unit
* @param baseUnit the unit being derived from. This does not have to be the base unit of measure
* @return the milli-unit
*/
@SuppressWarnings("checkstyle:methodname")
public static <U extends Unit> U Milli(U baseUnit) {
return Milli(
baseUnit, "Milli" + baseUnit.name().toLowerCase(Locale.ROOT), "m" + baseUnit.symbol());
}
/**
* Creates a unit equal to a millionth of the base unit, eg {@code Microseconds =
* Micro(Units.Seconds, "Microseconds", 'us")}.
*
* @param <U> the type of the unit
* @param baseUnit the unit being derived from. This does not have to be the base unit of measure
* @param name the name of the new derived unit
* @param symbol the symbol of the new derived unit
* @return the micro-unit
*/
@SuppressWarnings("checkstyle:methodname")
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();
}
/**
* Creates a unit equal to a millionth of the base unit, eg Microseconds = Micro(Units.Seconds).
*
* @param <U> the type of the unit
* @param baseUnit the unit being derived from. This does not have to be the base unit of measure
* @return the micro-unit
*/
@SuppressWarnings("checkstyle:methodname")
public static <U extends Unit> U Micro(U baseUnit) {
return Micro(
baseUnit, "Micro" + baseUnit.name().toLowerCase(Locale.ROOT), "u" + baseUnit.symbol());
}
/**
* Creates a unit equal to a thousand of the base unit, eg Kilograms = Kilo(Units.Grams).
*
* @param <U> the type of the unit
* @param baseUnit the unit being derived from. This does not have to be the base unit of measure
* @param name the name of the new derived unit
* @param symbol the symbol of the new derived unit
* @return the kilo-unit
*/
@SuppressWarnings("checkstyle:methodname")
public static <U extends Unit> U Kilo(U baseUnit, String name, String symbol) {
return derive(baseUnit).aggregate(1000).named(name).symbol(symbol).make();
}
/**
* Creates a unit equal to a thousand of the base unit, eg Kilograms = Kilo(Units.Grams).
*
* @param <U> the type of the unit
* @param baseUnit the unit being derived from. This does not have to be the base unit of measure
* @return the kilo-unit
*/
@SuppressWarnings("checkstyle:methodname")
public static <U extends Unit> U Kilo(U baseUnit) {
return Kilo(
baseUnit, "Kilo" + baseUnit.name().toLowerCase(Locale.ROOT), "K" + baseUnit.symbol());
}
/**
* Creates a new unit builder object based on a given input unit. The builder can be used to
* fluently describe a new unit in terms of its relation to the base unit.
*
* @param unit the base unit from which to derive a new unit
* @param <U> the dimension of the unit to derive
* @return a builder object
*/
public static <U extends Unit> UnitBuilder<U> derive(U unit) {
return new UnitBuilder<>(unit);
}
}

View File

@@ -0,0 +1,133 @@
// 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.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 Velocity<>(magnitude, toBaseUnits(magnitude), this);
}
@Override
public Velocity<D> ofBaseUnits(double baseUnitMagnitude) {
return new Velocity<>(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
@SuppressWarnings("unchecked")
public Velocity<D> zero() {
return (Velocity<D>) super.zero();
}
@Override
@SuppressWarnings("unchecked")
public Velocity<D> one() {
return (Velocity<D>) super.one();
}
/**
* 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

@@ -0,0 +1,108 @@
// 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.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 Voltage(magnitude, toBaseUnits(magnitude), this);
}
@Override
public Voltage ofBaseUnits(double baseUnitMagnitude) {
return new Voltage(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
}
@Override
public Voltage zero() {
return (Voltage) super.zero();
}
@Override
public Voltage one() {
return (Voltage) super.one();
}
@Override
public VelocityUnit<VoltageUnit> per(TimeUnit period) {
return VelocityUnit.combine(this, period);
}
/**
* Combines this unit of voltage with a unit of current to form a unit of resistance.
*
* @param currentUnit the unit of current
* @return the combined resistance unit
*/
public ResistanceUnit per(CurrentUnit currentUnit) {
return ResistanceUnit.combine(this, currentUnit);
}
/**
* 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,346 @@
// 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.collections;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
/**
* A variant on {@code java.util.HashMap<K, V>} that uses primitive long ints for map keys instead
* of autoboxed Long objects like would be used for a {@code Map<Long, V>}.
*
* @param <V> the type of the values stored in the map
*/
public class LongToObjectHashMap<V> {
private static final int kInitialSize = 0;
private static final int kInitialCapacity = 8; // NOTE: must be a power of two
/**
* The default load factor of the hashmap. If the ratio of the number of entries to the map's
* capacity exceeds this value, the map will be resized (doubled capacity) in order for more
* values to be easily inserted.
*/
private static final double kLoadFactor = 75.00 / 100;
/** The current number of key-value pairs in the map. */
private int m_size = kInitialSize;
/**
* The current maximum capacity of the map. Note that it will be resized before m_size reaches
* this value.
*/
private int m_capacity = kInitialCapacity;
/**
* The keys in the map. This is a sparse array, and the location of a key may not be equal to the
* result of calling {@link #bucket(long)} on that key. To handle hash collisions, if a bucket is
* already in use when trying to insert a value, the bucket number is incremented (wrapping around
* to 0 if it's equal to m_capacity) and <i>that</i> bucket is checked to see if it's available.
* This process continues until an empty bucket is found (which is guaranteed because m_size is
* always less than m_capacity).
*/
private long[] m_keys = new long[m_capacity];
/** Tracks which buckets are actually used (have a key-value mapping). */
private boolean[] m_uses = new boolean[m_capacity];
/**
* The values in the map. See the documentation for m_keys for how indexing into this array works.
*/
@SuppressWarnings("unchecked")
private V[] m_values = (V[]) new Object[m_capacity];
/** Default constructor. */
public LongToObjectHashMap() {}
/**
* Puts a value {@code value} corresponding to key {@code key} in the map.
*
* @param key the associated key
* @param value the value to insert
* @return the previous value that was mapped to the key, or null if no such value existed
*/
public V put(long key, V value) {
int bucket = bucket(key);
// Increment the bucket until we hit an open space (there's always going to be at least one)
while (m_uses[bucket]) {
if (m_keys[bucket] == key) {
// replace the existing value
var oldValue = m_values[bucket];
m_values[bucket] = value;
return oldValue;
}
bucket = safeIncrement(bucket);
}
m_uses[bucket] = true;
m_keys[bucket] = key;
m_values[bucket] = value;
m_size++;
if (m_size > maxSize()) {
grow();
}
return null;
}
/**
* Gets the value associated with the given key.
*
* @param key the key to retrieve the value for
* @return the value mapped to the key, or null if the key is not in the map
*/
public V get(long key) {
int bucket = bucket(key);
while (m_uses[bucket]) {
if (m_keys[bucket] == key) {
// found it
return m_values[bucket];
}
bucket = safeIncrement(bucket);
}
return null;
}
/**
* Removes the value associated with the given key and returns it.
*
* @param key the key to remove
* @return the value corresponding to the key, or null if the key is not in the map
*/
public V remove(long key) {
int bucket = bucket(key);
while (m_uses[bucket]) {
if (m_keys[bucket] == key) {
// found it
// TODO: Shrink the map when below a certain load factor
// Current use cases don't remove elements from the map, so there's not much use
// for shrinking at the moment.
m_size--;
m_keys[bucket] = 0L;
m_uses[bucket] = false;
var oldValue = m_values[bucket];
m_values[bucket] = null;
return oldValue;
}
bucket = safeIncrement(bucket);
}
return null;
}
/**
* Checks if a key is contained in the map.
*
* @param key the key to check
* @return true if the key has an associated value, false if not
*/
public boolean containsKey(long key) {
int bucket = bucket(key);
while (m_uses[bucket]) {
if (m_keys[bucket] == key) {
return true;
}
bucket = safeIncrement(bucket);
}
return false;
}
/** Clears and removes all entries from the map. */
public void clear() {
if (m_size == 0) {
// Nothing to do
return;
}
m_size = 0;
Arrays.fill(m_uses, false);
Arrays.fill(m_keys, 0L);
Arrays.fill(m_values, null);
}
/**
* Gets the number of key-value pairs currently contained in the map.
*
* @return the current size of the map
*/
public int size() {
return m_size;
}
// package-private for tests
int capacity() {
return m_capacity;
}
/**
* Checks if the map contains any entries.
*
* @return true if at least one entry is present, false otherwise
*/
public boolean isEmpty() {
return m_size == 0;
}
/**
* Gets the keys contained in the map. Ordering is not guaranteed. The returned set is read-only
* and immutable. This uses a custom class for primitive long values to avoid unnecessary
* autoboxing to {@code java.lang.Long}.
*
* @return a read-only set of keys
*/
public ReadOnlyPrimitiveLongSet keySet() {
// copy the sparse key array into a compact array
final long[] keys = new long[m_size];
int i = 0;
for (int bucket = 0; bucket < m_capacity; bucket++) {
if (m_uses[bucket]) {
keys[i] = m_keys[bucket];
i++;
}
}
return new ReadOnlyPrimitiveLongSet(keys);
}
/**
* Gets the values contained in the map. Ordering is not guaranteed. The returned collection is
* read-only and immutable.
*
* @return a read-only collection of values
*/
public Collection<V> values() {
Collection<V> values = new ArrayList<>();
for (int bucket = 0; bucket < m_capacity; bucket++) {
if (m_uses[bucket]) {
values.add(m_values[bucket]);
}
}
return List.copyOf(values); // return a readonly copy
}
/**
* Interface for map iterator function.
*
* @param <V> Value type.
*/
@FunctionalInterface
public interface IteratorFunction<V> {
/**
* Accepts a key-value pair from the map.
*
* @param key The key.
* @param value The value.
*/
void accept(long key, V value);
}
/**
* Iterates over every key-value pair in the map and passes them to the given function.
*
* @param function the function to apply to every key-value pair.
*/
public void forEach(IteratorFunction<? super V> function) {
for (int bucket = 0; bucket < m_capacity; bucket++) {
if (m_uses[bucket]) {
function.accept(m_keys[bucket], m_values[bucket]);
}
}
}
private void grow() {
final int currentSize = m_size;
final int oldCapacity = m_capacity;
if (oldCapacity * kLoadFactor >= currentSize) {
// We're below the maximum allowed size for the current capacity
// Nothing to do
return;
}
final int newCapacity = oldCapacity * 2;
final int newMask = newCapacity - 1;
final boolean[] oldUses = m_uses;
final long[] oldKeys = m_keys;
final V[] oldValues = m_values;
final boolean[] newUses = new boolean[newCapacity];
final long[] newKeys = new long[newCapacity];
@SuppressWarnings("unchecked")
final V[] newValues = (V[]) new Object[newCapacity];
for (int oldBucket = 0; oldBucket < oldCapacity; oldBucket++) {
if (!oldUses[oldBucket]) {
// Bucket is empty, skip
continue;
}
final long key = oldKeys[oldBucket];
final V value = oldValues[oldBucket];
int newBucket = (int) (hash(key) & newMask);
while (newUses[newBucket]) {
newBucket = (newBucket + 1) & newMask;
}
newUses[newBucket] = true;
newKeys[newBucket] = key;
newValues[newBucket] = value;
}
m_capacity = newCapacity;
m_uses = newUses;
m_keys = newKeys;
m_values = newValues;
}
private int maxSize() {
return (int) (m_capacity * kLoadFactor);
}
/**
* Calculates a hashcode for an input key. Does some bit shuffling to account for poor hash
* functions.
*
* @param key the key to hash
* @return a hashcode for the input key
*/
private long hash(long key) {
return 31 + (key ^ (key >>> 15) ^ (key >>> 31) ^ (key << 31));
}
/**
* The mask to use when translating a hashcode to a bucket index. Relies on m_capacity being a
* power of two.
*/
private int mask() {
return m_capacity - 1;
}
/**
* Calculates the desired bucket index for a particular key. Does nothing to handle the case where
* the calculated index is already in use by another key.
*
* @param key the key to get the bucket for
* @return the desired bucket index
*/
private int bucket(long key) {
var hash = hash(key);
return (int) (hash & mask());
}
/**
* Increments a bucket index by 1, wrapping around to 0 if the index is already at the maximum.
*
* @param bucket the index to increment
* @return the incremented bucket index
*/
private int safeIncrement(int bucket) {
return (bucket + 1) & mask();
}
}

View File

@@ -0,0 +1,130 @@
// 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.collections;
import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.stream.LongStream;
/** A read-only set of unique primitive {@code long} values. */
public class ReadOnlyPrimitiveLongSet implements Iterable<Long> {
private final long[] m_values;
/**
* Creates a new set from the given values. These values do not have to be unique.
*
* @param values the values that belong to the set.
*/
@SuppressWarnings({"PMD.ForLoopCanBeForeach", "ForLoopReplaceableByForEach"})
public ReadOnlyPrimitiveLongSet(long... values) {
// initial size is the upper limit
long[] uniqueValues = new long[values.length];
int numUniqueValues = 0;
boolean seenZero = false;
// copy the set of unique values to our array
// using indexed for-loops to avoid allocations
copyLoop:
for (int i = 0; i < values.length; i++) {
long value = values[i];
if (value == 0 && !seenZero) {
// special case to support zero
seenZero = true;
} else {
for (int j = 0; j < uniqueValues.length; j++) {
long uniqueValue = uniqueValues[j];
if (uniqueValue == value) {
continue copyLoop;
}
}
}
uniqueValues[numUniqueValues] = value;
numUniqueValues++;
}
if (numUniqueValues == values.length) {
// all input values were unique, no need to truncate
m_values = uniqueValues;
} else {
// truncate the array to remove trailing empty space
m_values = Arrays.copyOf(uniqueValues, numUniqueValues);
}
}
/**
* Checks if the set contains a particular value.
*
* @param value the value to check for
* @return true if the value is in the set, false if not
*/
public boolean contains(long value) {
for (long mValue : m_values) {
if (mValue == value) {
return true;
}
}
return false;
}
/**
* Retrieves the number of elements in the set.
*
* @return the number of elements in the set
*/
public int size() {
return m_values.length;
}
/**
* Checks if the set is empty, i.e. contains no values.
*
* @return true if there are no values in the set, false otherwise.
*/
public boolean isEmpty() {
return size() == 0;
}
/**
* Creates a stream of primitive long values for the set.
*
* @return a sequential Stream over the elements in this collection
* @see Set#stream()
*/
public LongStream stream() {
return Arrays.stream(m_values);
}
/**
* Creates a new array that contains all of the values in the set.
*
* @return an array containing all the values in the set
*/
public long[] toArray() {
return Arrays.copyOf(m_values, m_values.length);
}
@Override
public Iterator<Long> iterator() {
return new Iterator<>() {
private int m_index = 0;
@Override
public boolean hasNext() {
return m_index < ReadOnlyPrimitiveLongSet.this.size();
}
@Override
public Long next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return ReadOnlyPrimitiveLongSet.this.m_values[m_index++];
}
};
}
}