From d6f7cb92ff7e02448c23a03defa21c80bea00826 Mon Sep 17 00:00:00 2001 From: Muximize Date: Mon, 5 Dec 2022 19:34:55 +0100 Subject: [PATCH] Add UnitMath.Clamp(value, min, max) (#1157) * Add UnitMath.Clamp(value, min, max) * Change Clamp to convert min/max to the unit of value, following the principle of least surprise. * Update UnitMath.cs Co-authored-by: Marnix Co-authored-by: Andreas Gullberg Larsen --- UnitsNet.Tests/UnitMathTests.cs | 35 ++++++++++++++++++++++++++++ UnitsNet/UnitMath.cs | 41 +++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/UnitsNet.Tests/UnitMathTests.cs b/UnitsNet.Tests/UnitMathTests.cs index 1951549863..8fbb83ada1 100644 --- a/UnitsNet.Tests/UnitMathTests.cs +++ b/UnitsNet.Tests/UnitMathTests.cs @@ -318,5 +318,40 @@ public void SumOfLengthsWithSelectorCalculatesCorrectly() Assert.Equal(150, sum.Value); Assert.Equal(LengthUnit.Centimeter, sum.Unit); } + + [Fact] + public void ClampCalculatesCorrectly() + { + var min = Length.FromMeters(-1); + var max = Length.FromCentimeters(150); + + var value1 = Length.FromMillimeters(33); + + Length clampedValue = UnitMath.Clamp(value1, min, max); + Assert.Equal(33, clampedValue.Value); + Assert.Equal(LengthUnit.Millimeter, clampedValue.Unit); + + var value2 = Length.FromMillimeters(-1500); + + Length clampedMin = UnitMath.Clamp(value2, min, max); + Assert.Equal(-1000, clampedMin.Value); + Assert.Equal(LengthUnit.Millimeter, clampedMin.Unit); + + var value3 = Length.FromMillimeters(2000); + + Length clampedMax = UnitMath.Clamp(value3, min, max); + Assert.Equal(1500, clampedMax.Value); + Assert.Equal(LengthUnit.Millimeter, clampedMax.Unit); + } + + [Fact] + public void ClampMinGreaterThanMaxThrowsException() + { + var min = Length.FromMeters(2); + var max = Length.FromCentimeters(150); + var value = Length.FromMillimeters(33); + + Assert.Throws(() => UnitMath.Clamp(value, min, max)); + } } } diff --git a/UnitsNet/UnitMath.cs b/UnitsNet/UnitMath.cs index d684c77e66..472f25c9b7 100644 --- a/UnitsNet/UnitMath.cs +++ b/UnitsNet/UnitMath.cs @@ -197,5 +197,46 @@ public static TQuantity Average(this IEnumerable so { return source.Select(selector).Average(unitType); } + + /// Returns clamped to the inclusive range of and . + /// The value to be clamped. + /// The lower bound of the result. + /// The upper bound of the result. + /// + /// if . + /// + /// -or- + /// + /// (converted to value.Unit) if < . + /// + /// -or- + /// + /// (converted to value.Unit) if < . + /// + /// + /// cannot be greater than . + /// + public static TQuantity Clamp(TQuantity value, TQuantity min, TQuantity max) where TQuantity : IComparable, IQuantity + { + var minValue = (TQuantity)min.ToUnit(value.Unit); + var maxValue = (TQuantity)max.ToUnit(value.Unit); + + if (minValue.CompareTo(maxValue) > 0) + { + throw new ArgumentException($"min ({min}) cannot be greater than max ({max})", nameof(min)); + } + + if (value.CompareTo(minValue) < 0) + { + return minValue; + } + + if (value.CompareTo(maxValue) > 0) + { + return maxValue; + } + + return value; + } } }