diff --git a/wpiunits/generate_units.py b/wpiunits/generate_units.py index 3f35152b61b..58eaa134d53 100755 --- a/wpiunits/generate_units.py +++ b/wpiunits/generate_units.py @@ -136,6 +136,30 @@ def output(output_dir, outfn: str, contents: str): "Force": "Torque", }, "divide": {"Time": "LinearVelocity", "LinearVelocity": "Time"}, + "extra": inspect.cleandoc( + """ + /** Returns the hypotenuse (sqrt(a^2 + b^2)) between two Distances. + * The result is returned in the units of the first parameter. + * @param a the first distance + * @param b the second distance + * @return the hypotenuse between a and b + */ + static Distance hypot(Distance a, Distance b) { + return a.unit().ofBaseUnits( + Math.hypot(a.in(a.unit().getBaseUnit()), b.in(b.unit().getBaseUnit())) + ); + } + + /** Returns the hypotenuse (sqrt(this^2 + other^2)) between two Distances. + * The result is returned in the units of the first parameter. + * @param other the second distance + * @return the hypotenuse between this and other + */ + default Distance hypot(Distance other) { + return hypot(this, other); + } + """ + ), }, "Energy": { "base_unit": "Joules", diff --git a/wpiunits/src/generated/main/java/edu/wpi/first/units/measure/Distance.java b/wpiunits/src/generated/main/java/edu/wpi/first/units/measure/Distance.java index e0f53a620e2..a80512b5f4c 100644 --- a/wpiunits/src/generated/main/java/edu/wpi/first/units/measure/Distance.java +++ b/wpiunits/src/generated/main/java/edu/wpi/first/units/measure/Distance.java @@ -780,5 +780,25 @@ default Per divide(Voltage divisor) { default Per per(VoltageUnit divisorUnit) { return div(divisorUnit.one()); } + + /** Returns the hypotenuse (sqrt(a^2 + b^2)) between two Distances. + * The result is returned in the units of the first parameter. + * @param a the first distance + * @param b the second distance + * @return the hypotenuse between a and b + */ + static Distance hypot(Distance a, Distance b) { + return a.unit().ofBaseUnits( + Math.hypot(a.in(a.unit().getBaseUnit()), b.in(b.unit().getBaseUnit())) + ); + } + /** Returns the hypotenuse (sqrt(this^2 + other^2)) between two Distances. + * The result is returned in the units of the first parameter. + * @param other the second distance + * @return the hypotenuse between this and other + */ + default Distance hypot(Distance other) { + return hypot(this, other); + } } 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 25667d8f09d..7f7c720e81a 100644 --- a/wpiunits/src/test/java/edu/wpi/first/units/MeasureTest.java +++ b/wpiunits/src/test/java/edu/wpi/first/units/MeasureTest.java @@ -114,6 +114,30 @@ void testAs() { assertEquals(1, m.in(Units.Feet), Measure.EQUIVALENCE_THRESHOLD); } + @Test + void testHypot() { + Distance a = Units.Meters.of(6); + Distance b = Units.Meters.of(8); + + // Static method on Distance + Distance resStatic = Distance.hypot(a, b); + assertEquals(Units.Meters.of(10), resStatic); + + // Instance method on Distance delegating to static + Distance resInstance = a.hypot(b); + assertEquals(Units.Meters.of(10), resInstance); + + // Mixed units: 3 feet and 48 inches (4 feet) -> hypot = 5 feet + Distance f3 = Units.Feet.of(3); + Distance in48 = Units.Inches.of(48); + + Distance mixed = Distance.hypot(f3, in48); + assertTrue(mixed.isEquivalent(Units.Feet.of(5))); + + Distance mixedInstance = f3.hypot(in48); + assertTrue(mixedInstance.isEquivalent(Units.Feet.of(5))); + } + @Test void testPerMeasureTime() { var measure = Units.Kilograms.of(144);