From 46bfa17b93839ac0d303dc7660958bd8503361dc Mon Sep 17 00:00:00 2001 From: Oliver Booth Date: Wed, 13 Jul 2022 12:09:37 +0100 Subject: [PATCH] Add vector and point component rounding (#65) --- CHANGELOG.md | 7 ++++ X10D.Tests/src/Drawing/PointFTests.cs | 20 ++++++++++ X10D.Tests/src/Numerics/Vector2Tests.cs | 20 ++++++++++ X10D.Tests/src/Numerics/Vector3Tests.cs | 22 +++++++++++ X10D.Tests/src/Numerics/Vector4Tests.cs | 24 ++++++++++++ .../Assets/Tests/Numerics/Vector2Tests.cs | 24 ++++++++++++ .../Assets/Tests/Numerics/Vector3Tests.cs | 26 +++++++++++++ .../Assets/Tests/Numerics/Vector4Tests.cs | 28 ++++++++++++++ X10D.Unity/src/Numerics/Vector2Extensions.cs | 28 ++++++++++++++ X10D.Unity/src/Numerics/Vector3Extensions.cs | 29 ++++++++++++++ X10D.Unity/src/Numerics/Vector4Extensions.cs | 30 +++++++++++++++ X10D/src/Drawing/PointFExtensions.cs | 36 ++++++++++++++++++ X10D/src/Numerics/Vector2Extensions.cs | 36 ++++++++++++++++++ X10D/src/Numerics/Vector3Extensions.cs | 37 ++++++++++++++++++ X10D/src/Numerics/Vector4Extensions.cs | 38 +++++++++++++++++++ 15 files changed, 405 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03e3f3d..a96bb34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - X10D: Added `Point.ToSize()` - X10D: Added `Point.ToSizeF()` - X10D: Added `Point.ToVector2()` +- X10D: Added `PointF.Round([float])` - X10D: Added `PointF.ToSizeF()` - X10D: Added `PointF.ToVector2()` for .NET < 6 - X10D: Added `PopCount()` for built-in integer types @@ -22,10 +23,13 @@ - X10D: Added `Quaternion.Multiply(Vector3)` - this functions as an equivalent to Unity's `Quaternion * Vector3` operator - X10D: Added `Vector2.Deconstruct()` - X10D: Added `Vector2.IsOnLine(LineF)`, `Vector2.IsOnLine(PointF, PointF)`, and `Vector2.IsOnLine(Vector2, Vector2)` +- X10D: Added `Vector2.Round([float])` - X10D: Added `Vector2.ToPointF()` - X10D: Added `Vector2.ToSizeF()` - X10D: Added `Vector3.Deconstruct()` +- X10D: Added `Vector3.Round([float])` - X10D: Added `Vector4.Deconstruct()` +- X10D: Added `Vector4.Round([float])` - X10D.Unity: Added `DebugEx`, which mimics `UnityEngine.Debug` while offering more useful primitive drawing methods - X10D.Unity: Added `System.Drawing.Color.ToUnityColor()` - X10D.Unity: Added `System.Drawing.Color.ToUnityColor32()` @@ -46,6 +50,7 @@ - X10D.Unity: Added `Vector2.Deconstruct()` - X10D.Unity: Added `Vector2.IsOnLine(LineF)`, `Vector2.IsOnLine(PointF, PointF)`, and `Vector2.IsOnLine(Vector2, Vector2)` - X10D.Unity: Added `Vector2Int.IsOnLine(LineF)`, `Vector2Int.IsOnLine(PointF, PointF)`, `Vector2Int.IsOnLine(Vector2, Vector2)`, and `Vector2Int.IsOnLine(Vector2Int, Vector2Int)` +- X10D.Unity: Added `Vector2.Round([float])` - X10D.Unity: Added `Vector2.ToSystemPointF()` - X10D.Unity: Added `Vector2.ToSystemSizeF()` - X10D.Unity: Added `Vector2Int.Deconstruct()` @@ -55,12 +60,14 @@ - X10D.Unity: Added `Vector2Int.WithX()` - X10D.Unity: Added `Vector2Int.WithY()` - X10D.Unity: Added `Vector3.Deconstruct()` +- X10D.Unity: Added `Vector3.Round([float])` - X10D.Unity: Added `Vector3Int.Deconstruct()` - X10D.Unity: Added `Vector3Int.ToSystemVector()` - X10D.Unity: Added `Vector3Int.WithX()` - X10D.Unity: Added `Vector3Int.WithY()` - X10D.Unity: Added `Vector3Int.WithZ()` - X10D.Unity: Added `Vector4.Deconstruct()` +- X10D.Unity: Added `Vector4.Round([float])` ### Changed - X10D.Unity: Obsolesced `Singleton` diff --git a/X10D.Tests/src/Drawing/PointFTests.cs b/X10D.Tests/src/Drawing/PointFTests.cs index 577aa78..a21cb2b 100644 --- a/X10D.Tests/src/Drawing/PointFTests.cs +++ b/X10D.Tests/src/Drawing/PointFTests.cs @@ -8,6 +8,26 @@ namespace X10D.Tests.Drawing; [TestClass] public class PointFTests { + [TestMethod] + public void Round_ShouldRoundToNearestInteger_GivenNoParameters() + { + var point = new PointF(1.5f, 2.6f); + var rounded = point.Round(); + + Assert.AreEqual(2, rounded.X); + Assert.AreEqual(3, rounded.Y); + } + + [TestMethod] + public void Round_ShouldRoundToNearest10_GivenPrecision10() + { + var point = new PointF(1.5f, 25.2f); + var rounded = point.Round(10); + + Assert.AreEqual(0, rounded.X); + Assert.AreEqual(30, rounded.Y); + } + [TestMethod] public void ToSizeF_ShouldReturnSize_WithEquivalentMembers() { diff --git a/X10D.Tests/src/Numerics/Vector2Tests.cs b/X10D.Tests/src/Numerics/Vector2Tests.cs index b20a300..5181156 100644 --- a/X10D.Tests/src/Numerics/Vector2Tests.cs +++ b/X10D.Tests/src/Numerics/Vector2Tests.cs @@ -18,6 +18,26 @@ public class Vector2Tests Assert.AreEqual(2, y); } + [TestMethod] + public void Round_ShouldRoundToNearestInteger_GivenNoParameters() + { + var vector = new Vector2(1.5f, 2.6f); + var rounded = vector.Round(); + + Assert.AreEqual(2, rounded.X); + Assert.AreEqual(3, rounded.Y); + } + + [TestMethod] + public void Round_ShouldRoundToNearest10_GivenPrecision10() + { + var vector = new Vector2(1.5f, 25.2f); + var rounded = vector.Round(10); + + Assert.AreEqual(0, rounded.X); + Assert.AreEqual(30, rounded.Y); + } + [TestMethod] public void ToPointF_ShouldReturnPoint_WithEquivalentMembers() { diff --git a/X10D.Tests/src/Numerics/Vector3Tests.cs b/X10D.Tests/src/Numerics/Vector3Tests.cs index 037c944..10b1ad0 100644 --- a/X10D.Tests/src/Numerics/Vector3Tests.cs +++ b/X10D.Tests/src/Numerics/Vector3Tests.cs @@ -18,6 +18,28 @@ public class Vector3Tests Assert.AreEqual(3, z); } + [TestMethod] + public void Round_ShouldRoundToNearestInteger_GivenNoParameters() + { + var vector = new Vector3(1.5f, 2.6f, -5.2f); + var rounded = vector.Round(); + + Assert.AreEqual(2, rounded.X); + Assert.AreEqual(3, rounded.Y); + Assert.AreEqual(-5, rounded.Z); + } + + [TestMethod] + public void Round_ShouldRoundToNearest10_GivenPrecision10() + { + var vector = new Vector3(1.5f, 25.2f, -12.5f); + var rounded = vector.Round(10); + + Assert.AreEqual(0, rounded.X); + Assert.AreEqual(30, rounded.Y); + Assert.AreEqual(-10, rounded.Z); + } + [TestMethod] public void WithX_ShouldReturnVectorWithNewX_GivenVector() { diff --git a/X10D.Tests/src/Numerics/Vector4Tests.cs b/X10D.Tests/src/Numerics/Vector4Tests.cs index 3b8e396..88dbac7 100644 --- a/X10D.Tests/src/Numerics/Vector4Tests.cs +++ b/X10D.Tests/src/Numerics/Vector4Tests.cs @@ -19,6 +19,30 @@ public class Vector4Tests Assert.AreEqual(4, w); } + [TestMethod] + public void Round_ShouldRoundToNearestInteger_GivenNoParameters() + { + var vector = new Vector4(1.5f, 2.6f, -5.2f, 0.3f); + var rounded = vector.Round(); + + Assert.AreEqual(2, rounded.X); + Assert.AreEqual(3, rounded.Y); + Assert.AreEqual(-5, rounded.Z); + Assert.AreEqual(0, rounded.W); + } + + [TestMethod] + public void Round_ShouldRoundToNearest10_GivenPrecision10() + { + var vector = new Vector4(1.5f, 25.2f, -12.5f, 101.2f); + var rounded = vector.Round(10); + + Assert.AreEqual(0, rounded.X); + Assert.AreEqual(30, rounded.Y); + Assert.AreEqual(-10, rounded.Z); + Assert.AreEqual(100, rounded.W); + } + [TestMethod] public void WithW_ShouldReturnVectorWithNewW_GivenVector() { diff --git a/X10D.Unity.Tests/Assets/Tests/Numerics/Vector2Tests.cs b/X10D.Unity.Tests/Assets/Tests/Numerics/Vector2Tests.cs index 232a54b..3be36d0 100644 --- a/X10D.Unity.Tests/Assets/Tests/Numerics/Vector2Tests.cs +++ b/X10D.Unity.Tests/Assets/Tests/Numerics/Vector2Tests.cs @@ -22,6 +22,30 @@ namespace X10D.Unity.Tests.Numerics yield break; } + [UnityTest] + public IEnumerator Round_ShouldRoundToNearestInteger_GivenNoParameters() + { + var vector = new Vector2(1.5f, 2.6f); + var rounded = vector.Round(); + + Assert.AreEqual(2, rounded.x); + Assert.AreEqual(3, rounded.y); + + yield break; + } + + [UnityTest] + public IEnumerator Round_ShouldRoundToNearest10_GivenPrecision10() + { + var vector = new Vector2(1.5f, 25.2f); + var rounded = vector.Round(10); + + Assert.AreEqual(0, rounded.x); + Assert.AreEqual(30, rounded.y); + + yield break; + } + [UnityTest] public IEnumerator ToSystemPointF_ShouldReturnPoint_WithEquivalentMembers() { diff --git a/X10D.Unity.Tests/Assets/Tests/Numerics/Vector3Tests.cs b/X10D.Unity.Tests/Assets/Tests/Numerics/Vector3Tests.cs index 8eaf0c0..08ebed9 100644 --- a/X10D.Unity.Tests/Assets/Tests/Numerics/Vector3Tests.cs +++ b/X10D.Unity.Tests/Assets/Tests/Numerics/Vector3Tests.cs @@ -23,6 +23,32 @@ namespace X10D.Unity.Tests.Numerics yield break; } + [UnityTest] + public IEnumerator Round_ShouldRoundToNearestInteger_GivenNoParameters() + { + var vector = new Vector3(1.5f, 2.6f, -5.2f); + var rounded = vector.Round(); + + Assert.AreEqual(2, rounded.x); + Assert.AreEqual(3, rounded.y); + Assert.AreEqual(-5, rounded.z); + + yield break; + } + + [UnityTest] + public IEnumerator Round_ShouldRoundToNearest10_GivenPrecision10() + { + var vector = new Vector3(1.5f, 25.2f, -12.5f); + var rounded = vector.Round(10); + + Assert.AreEqual(0, rounded.x); + Assert.AreEqual(30, rounded.y); + Assert.AreEqual(-10, rounded.z); + + yield break; + } + [UnityTest] public IEnumerator ToSystemVector_ShouldReturnVector_WithEqualComponents() { diff --git a/X10D.Unity.Tests/Assets/Tests/Numerics/Vector4Tests.cs b/X10D.Unity.Tests/Assets/Tests/Numerics/Vector4Tests.cs index 886420d..b943406 100644 --- a/X10D.Unity.Tests/Assets/Tests/Numerics/Vector4Tests.cs +++ b/X10D.Unity.Tests/Assets/Tests/Numerics/Vector4Tests.cs @@ -24,6 +24,34 @@ namespace X10D.Unity.Tests.Numerics yield break; } + [UnityTest] + public IEnumerator Round_ShouldRoundToNearestInteger_GivenNoParameters() + { + var vector = new Vector4(1.5f, 2.6f, -5.2f, 0.3f); + var rounded = vector.Round(); + + Assert.AreEqual(2, rounded.x); + Assert.AreEqual(3, rounded.y); + Assert.AreEqual(-5, rounded.z); + Assert.AreEqual(0, rounded.w); + + yield break; + } + + [UnityTest] + public IEnumerator Round_ShouldRoundToNearest10_GivenPrecision10() + { + var vector = new Vector4(1.5f, 25.2f, -12.5f, 101.2f); + var rounded = vector.Round(10); + + Assert.AreEqual(0, rounded.x); + Assert.AreEqual(30, rounded.y); + Assert.AreEqual(-10, rounded.z); + Assert.AreEqual(100, rounded.w); + + yield break; + } + [UnityTest] public IEnumerator ToSystemVector_ShouldReturnVector_WithEqualComponents() { diff --git a/X10D.Unity/src/Numerics/Vector2Extensions.cs b/X10D.Unity/src/Numerics/Vector2Extensions.cs index 23ff4da..cad8af5 100644 --- a/X10D.Unity/src/Numerics/Vector2Extensions.cs +++ b/X10D.Unity/src/Numerics/Vector2Extensions.cs @@ -3,6 +3,7 @@ using System.Drawing; using System.Runtime.CompilerServices; using UnityEngine; using X10D.Drawing; +using X10D.Math; using X10D.Numerics; namespace X10D.Unity.Numerics; @@ -74,6 +75,33 @@ public static class Vector2Extensions return point.ToSystemVector().IsOnLine(start.ToSystemVector(), end.ToSystemVector()); } + /// + /// Rounds the components in the current to the nearest integer. + /// + /// The vector whose components to round. + /// The rounded vector. + [Pure] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 Round(this Vector2 vector) + { + return vector.Round(1.0f); + } + + /// + /// Rounds the components in the current to the nearest multiple of a specified number. + /// + /// The vector whose components to round. + /// The nearest multiple to which the components should be rounded. + /// The rounded vector. + [Pure] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 Round(this Vector2 vector, float nearest) + { + float x = vector.x.Round(nearest); + float y = vector.y.Round(nearest); + return new Vector2(x, y); + } + /// /// Converts the current into a . /// diff --git a/X10D.Unity/src/Numerics/Vector3Extensions.cs b/X10D.Unity/src/Numerics/Vector3Extensions.cs index 2de1804..3ef39f1 100644 --- a/X10D.Unity/src/Numerics/Vector3Extensions.cs +++ b/X10D.Unity/src/Numerics/Vector3Extensions.cs @@ -1,6 +1,7 @@ using System.Diagnostics.Contracts; using System.Runtime.CompilerServices; using UnityEngine; +using X10D.Math; namespace X10D.Unity.Numerics; @@ -23,6 +24,34 @@ public static class Vector3Extensions z = vector.z; } + /// + /// Rounds the components in the current to the nearest integer. + /// + /// The vector whose components to round. + /// The rounded vector. + [Pure] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 Round(this Vector3 vector) + { + return vector.Round(1.0f); + } + + /// + /// Rounds the components in the current to the nearest multiple of a specified number. + /// + /// The vector whose components to round. + /// The nearest multiple to which the components should be rounded. + /// The rounded vector. + [Pure] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 Round(this Vector3 vector, float nearest) + { + float x = vector.x.Round(nearest); + float y = vector.y.Round(nearest); + float z = vector.z.Round(nearest); + return new Vector3(x, y, z); + } + /// /// Converts the current vector to a . /// diff --git a/X10D.Unity/src/Numerics/Vector4Extensions.cs b/X10D.Unity/src/Numerics/Vector4Extensions.cs index 2ccef16..1215f78 100644 --- a/X10D.Unity/src/Numerics/Vector4Extensions.cs +++ b/X10D.Unity/src/Numerics/Vector4Extensions.cs @@ -1,6 +1,7 @@ using System.Diagnostics.Contracts; using System.Runtime.CompilerServices; using UnityEngine; +using X10D.Math; namespace X10D.Unity.Numerics; @@ -25,6 +26,35 @@ public static class Vector4Extensions w = vector.w; } + /// + /// Rounds the components in the current to the nearest integer. + /// + /// The vector whose components to round. + /// The rounded vector. + [Pure] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 Round(this Vector4 vector) + { + return vector.Round(1.0f); + } + + /// + /// Rounds the components in the current to the nearest multiple of a specified number. + /// + /// The vector whose components to round. + /// The nearest multiple to which the components should be rounded. + /// The rounded vector. + [Pure] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 Round(this Vector4 vector, float nearest) + { + float x = vector.x.Round(nearest); + float y = vector.y.Round(nearest); + float z = vector.z.Round(nearest); + float w = vector.w.Round(nearest); + return new Vector4(x, y, z, w); + } + /// /// Converts the current vector to a . /// diff --git a/X10D/src/Drawing/PointFExtensions.cs b/X10D/src/Drawing/PointFExtensions.cs index d7424f5..a464400 100644 --- a/X10D/src/Drawing/PointFExtensions.cs +++ b/X10D/src/Drawing/PointFExtensions.cs @@ -2,6 +2,7 @@ using System.Drawing; using System.Numerics; using System.Runtime.CompilerServices; +using X10D.Math; namespace X10D.Drawing; @@ -75,6 +76,41 @@ public static class PointFExtensions return point.IsOnLine(new LineF(start, end)); } + /// + /// Rounds the components in the current to the nearest integer. + /// + /// The point whose components to round. + /// The rounded point. + [Pure] +#if NETSTANDARD2_1 + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#else + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] +#endif + public static PointF Round(this PointF point) + { + return point.Round(1.0f); + } + + /// + /// Rounds the components in the current to the nearest multiple of a specified number. + /// + /// The point whose components to round. + /// The nearest multiple to which the components should be rounded. + /// The rounded point. + [Pure] +#if NETSTANDARD2_1 + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#else + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] +#endif + public static PointF Round(this PointF point, float nearest) + { + float x = point.X.Round(nearest); + float y = point.Y.Round(nearest); + return new PointF(x, y); + } + /// /// Converts the current to a . /// diff --git a/X10D/src/Numerics/Vector2Extensions.cs b/X10D/src/Numerics/Vector2Extensions.cs index 6ec710d..ff51e75 100644 --- a/X10D/src/Numerics/Vector2Extensions.cs +++ b/X10D/src/Numerics/Vector2Extensions.cs @@ -3,6 +3,7 @@ using System.Drawing; using System.Numerics; using System.Runtime.CompilerServices; using X10D.Drawing; +using X10D.Math; namespace X10D.Numerics; @@ -88,6 +89,41 @@ public static class Vector2Extensions return point.IsOnLine(new LineF(start, end)); } + /// + /// Rounds the components in the current to the nearest integer. + /// + /// The vector whose components to round. + /// The rounded vector. + [Pure] +#if NETSTANDARD2_1 + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#else + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] +#endif + public static Vector2 Round(this Vector2 vector) + { + return vector.Round(1.0f); + } + + /// + /// Rounds the components in the current to the nearest multiple of a specified number. + /// + /// The vector whose components to round. + /// The nearest multiple to which the components should be rounded. + /// The rounded vector. + [Pure] +#if NETSTANDARD2_1 + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#else + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] +#endif + public static Vector2 Round(this Vector2 vector, float nearest) + { + float x = vector.X.Round(nearest); + float y = vector.Y.Round(nearest); + return new Vector2(x, y); + } + /// /// Converts the current to a . /// diff --git a/X10D/src/Numerics/Vector3Extensions.cs b/X10D/src/Numerics/Vector3Extensions.cs index 78a87e8..fd81345 100644 --- a/X10D/src/Numerics/Vector3Extensions.cs +++ b/X10D/src/Numerics/Vector3Extensions.cs @@ -1,6 +1,7 @@ using System.Diagnostics.Contracts; using System.Numerics; using System.Runtime.CompilerServices; +using X10D.Math; namespace X10D.Numerics; @@ -23,6 +24,42 @@ public static class Vector3Extensions z = vector.Z; } + /// + /// Rounds the components in the current to the nearest integer. + /// + /// The vector whose components to round. + /// The rounded vector. + [Pure] +#if NETSTANDARD2_1 + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#else + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] +#endif + public static Vector3 Round(this Vector3 vector) + { + return vector.Round(1.0f); + } + + /// + /// Rounds the components in the current to the nearest multiple of a specified number. + /// + /// The vector whose components to round. + /// The nearest multiple to which the components should be rounded. + /// The rounded vector. + [Pure] +#if NETSTANDARD2_1 + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#else + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] +#endif + public static Vector3 Round(this Vector3 vector, float nearest) + { + float x = vector.X.Round(nearest); + float y = vector.Y.Round(nearest); + float z = vector.Z.Round(nearest); + return new Vector3(x, y, z); + } + /// /// Returns a vector whose Y and Z components are the same as the specified vector, and whose X component is a new value. /// diff --git a/X10D/src/Numerics/Vector4Extensions.cs b/X10D/src/Numerics/Vector4Extensions.cs index 7ab1085..81e3e81 100644 --- a/X10D/src/Numerics/Vector4Extensions.cs +++ b/X10D/src/Numerics/Vector4Extensions.cs @@ -1,6 +1,7 @@ using System.Diagnostics.Contracts; using System.Numerics; using System.Runtime.CompilerServices; +using X10D.Math; namespace X10D.Numerics; @@ -25,6 +26,43 @@ public static class Vector4Extensions w = vector.W; } + /// + /// Rounds the components in the current to the nearest integer. + /// + /// The vector whose components to round. + /// The rounded vector. + [Pure] +#if NETSTANDARD2_1 + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#else + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] +#endif + public static Vector4 Round(this Vector4 vector) + { + return vector.Round(1.0f); + } + + /// + /// Rounds the components in the current to the nearest multiple of a specified number. + /// + /// The vector whose components to round. + /// The nearest multiple to which the components should be rounded. + /// The rounded vector. + [Pure] +#if NETSTANDARD2_1 + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#else + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] +#endif + public static Vector4 Round(this Vector4 vector, float nearest) + { + float x = vector.X.Round(nearest); + float y = vector.Y.Round(nearest); + float z = vector.Z.Round(nearest); + float w = vector.W.Round(nearest); + return new Vector4(x, y, z, w); + } + /// /// Returns a vector whose Y, Z, and W components are the same as the specified vector, and whose X component is a new /// value.