[wpiunits] Java units API rewrite (#6958)

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

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

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

View File

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