diff --git a/wpiunits/src/main/java/edu/wpi/first/units/Measure.java b/wpiunits/src/main/java/edu/wpi/first/units/Measure.java index eb5b7a07ae..9ae27846a9 100644 --- a/wpiunits/src/main/java/edu/wpi/first/units/Measure.java +++ b/wpiunits/src/main/java/edu/wpi/first/units/Measure.java @@ -137,16 +137,29 @@ public interface Measure> extends Comparable> { } /** - * Divides this measurement by some constant divisor and returns the result. This is equivalent to - * {@code divide(divisor.baseUnitMagnitude())} + * Divides this measurement by another measure and performs some dimensional analysis to reduce + * the units. * - * @param divisor the dimensionless measure to divide by + * @param the type of the other measure to multiply by + * @param other the unit to multiply by * @return the resulting measure - * @see #divide(double) - * @see #times(double) */ - default Measure divide(Measure divisor) { - return divide(divisor.baseUnitMagnitude()); + default > Measure divide(Measure other) { + if (unit().getBaseUnit().equals(other.unit().getBaseUnit())) { + return Units.Value.ofBaseUnits(baseUnitMagnitude() / other.baseUnitMagnitude()); + } + if (other.unit() instanceof Dimensionless) { + return divide(other.baseUnitMagnitude()); + } + if (other.unit() instanceof Velocity velocity + && velocity.getUnit().getBaseUnit().equals(unit().getBaseUnit())) { + return times(velocity.reciprocal().ofBaseUnits(1 / other.baseUnitMagnitude())); + } + if (other.unit() instanceof Per per + && per.numerator().getBaseUnit().equals(unit().getBaseUnit())) { + return times(per.reciprocal().ofBaseUnits(1 / other.baseUnitMagnitude())); + } + return unit().per(other.unit()).ofBaseUnits(baseUnitMagnitude() / other.baseUnitMagnitude()); } /** diff --git a/wpiunits/src/main/java/edu/wpi/first/units/Per.java b/wpiunits/src/main/java/edu/wpi/first/units/Per.java index afde7a447f..897c405f43 100644 --- a/wpiunits/src/main/java/edu/wpi/first/units/Per.java +++ b/wpiunits/src/main/java/edu/wpi/first/units/Per.java @@ -109,6 +109,15 @@ public class Per, D extends Unit> extends Unit> { return m_denominator; } + /** + * Returns the reciprocal of this Per. + * + * @return the reciprocal + */ + public Per reciprocal() { + return m_denominator.per(m_numerator); + } + @Override public boolean equals(Object o) { if (this == o) { diff --git a/wpiunits/src/main/java/edu/wpi/first/units/Velocity.java b/wpiunits/src/main/java/edu/wpi/first/units/Velocity.java index e8a0dfc9d1..6fdfba10d0 100644 --- a/wpiunits/src/main/java/edu/wpi/first/units/Velocity.java +++ b/wpiunits/src/main/java/edu/wpi/first/units/Velocity.java @@ -157,6 +157,15 @@ public class Velocity> extends Unit> { return m_period; } + /** + * Returns the reciprocal of this velocity. + * + * @return the reciprocal + */ + public Per reciprocal() { + return m_period.per(m_unit); + } + @Override public boolean equals(Object o) { if (this == o) { diff --git a/wpiunits/src/test/java/edu/wpi/first/units/EncoderTest.java b/wpiunits/src/test/java/edu/wpi/first/units/EncoderTest.java index 1a4b568944..b78a4af6d7 100644 --- a/wpiunits/src/test/java/edu/wpi/first/units/EncoderTest.java +++ b/wpiunits/src/test/java/edu/wpi/first/units/EncoderTest.java @@ -7,7 +7,6 @@ package edu.wpi.first.units; import static edu.wpi.first.units.Units.Inches; import static edu.wpi.first.units.Units.Revolutions; import static edu.wpi.first.units.Units.Second; -import static edu.wpi.first.units.Units.Value; import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; @@ -46,14 +45,14 @@ class EncoderTest { @Test void testAsDistance() { - var ticksPerRevolution = Value.of(2048); + double ticksPerRevolution = 2048; var encoder = new Encoder(); // distance per rotation = (wheel circumference / gear ratio) // distance per tick = distance per rotation / ticks per rotation var wheelDiameter = Inches.of(6); - var gearRatio = Value.of(10); // 10:1 ratio + double gearRatio = 10; // 10:1 ratio Measure distancePerPulse = wheelDiameter.times(Math.PI).divide(gearRatio).divide(ticksPerRevolution); encoder.setDistancePerPulse(distancePerPulse); @@ -74,7 +73,7 @@ class EncoderTest { @Test void testAsRevolutions() { - var ticksPerRevolution = Value.of(2048); + double ticksPerRevolution = 2048; var encoder = new Encoder(); diff --git a/wpiunits/src/test/java/edu/wpi/first/units/MeasureTest.java b/wpiunits/src/test/java/edu/wpi/first/units/MeasureTest.java index dd943c449e..05f6398520 100644 --- a/wpiunits/src/test/java/edu/wpi/first/units/MeasureTest.java +++ b/wpiunits/src/test/java/edu/wpi/first/units/MeasureTest.java @@ -162,6 +162,40 @@ class MeasureTest { assertEquals(exampleUnit.of(42 * 17 / (12 * 25.4)), m3.times(m4)); } + @Test + void testDivideMeasure() { + // Dimensionless divide + var m1 = Units.Meters.of(6); + var m2 = Units.Value.of(3); + var result = m1.divide(m2); + assertEquals(m1.divide(m2).magnitude(), 2); + assertEquals(result.unit(), Units.Meters); + // Velocity divide + var m3 = Units.Meters.of(8); + var m4 = Units.Meters.per(Units.Second).of(4); + result = m3.divide(m4); + assertEquals(result.magnitude(), 2); + assertEquals(result.unit(), Units.Second); + // Per divide + var m5 = Units.Volts.of(6); + var m6 = Units.Volts.per(Units.Meter).of(2); + result = m5.divide(m6); + assertEquals(result.magnitude(), 3); + assertEquals(result.unit(), Units.Meter); + // Fallthrough divide + var m7 = Units.Seconds.of(10); + var m8 = Units.Amps.of(2); + result = m7.divide(m8); + assertEquals(result.magnitude(), 5); + assertEquals(result.unit(), Units.Seconds.per(Units.Amps)); + // Same base unit divide + var m9 = Units.Meters.of(8); + var m10 = Units.Meters.of(4); + result = m9.divide(m10); + assertEquals(result.magnitude(), 2); + assertEquals(result.unit(), Units.Value); + } + @Test void testToShortString() { var measure = Units.Volts.of(343);