diff --git a/modules/core/shared/src/main/scala/lucuma/core/math/Angle.scala b/modules/core/shared/src/main/scala/lucuma/core/math/Angle.scala index 757c29b6e..6d528a39b 100644 --- a/modules/core/shared/src/main/scala/lucuma/core/math/Angle.scala +++ b/modules/core/shared/src/main/scala/lucuma/core/math/Angle.scala @@ -300,6 +300,26 @@ object Angle extends AngleOptics { def -(a: Angle): Angle = Angle.fromMicroarcseconds(toMicroarcseconds - a.toMicroarcseconds) + /** + * Scalar multiplication of this angle and and natural number `a`. Exact + * @group Operations + */ + def *(a: Long): Angle = { + val µas = BigInt(toMicroarcseconds) * BigInt(a) + val µasʹ = (((µas % µasPer360) + µasPer360) % µasPer360).toLong + Angle.apply(µasʹ) + } + + /** + * Scalar multiplication of this angle and double precission number `a`. Approximate + * @group Operations + */ + def *(a: Double): Angle = { + val µas = toMicroarcseconds.toDouble * a + val µasʹ = (((µas % µasPer360) + µasPer360) % µasPer360).toLong + Angle.apply(µasʹ) + } + /** * This angle as an Offset.P. Exact, invertible. * diff --git a/modules/tests/shared/src/test/scala/lucuma/core/math/AngleSuite.scala b/modules/tests/shared/src/test/scala/lucuma/core/math/AngleSuite.scala index 8a9f29aa5..d48b2bf5f 100644 --- a/modules/tests/shared/src/test/scala/lucuma/core/math/AngleSuite.scala +++ b/modules/tests/shared/src/test/scala/lucuma/core/math/AngleSuite.scala @@ -182,4 +182,27 @@ final class AngleSuite extends munit.DisciplineSuite { assertEquals(a.tan, scala.math.tan(a.toDoubleRadians)) } } + + test("Scalar int multiplication") { + assertEquals(Angle.Angle0 * 2, Angle.Angle0) + assertEquals(Angle.Angle90 * 2, Angle.Angle180) + assertEquals(Angle.Angle90 * 4, Angle.Angle0) + assertEquals(Angle.Angle90 * -2, Angle.Angle180) + assertEquals(Angle.Angle90 * 10, Angle.Angle180) + assertEquals(Angle.Angle90 * 4000000, Angle.Angle0) + // Check overflow + assertEquals(Angle.Angle90 * 40000000, Angle.Angle0) + } + + test("Scalar double multiplication") { + assertEquals(Angle.Angle0 * 2.0, Angle.Angle0) + assertEquals(Angle.Angle90 * 2.0, Angle.Angle180) + assertEquals(Angle.Angle90 * 4.0, Angle.Angle0) + assertEquals(Angle.Angle90 * -2.0, Angle.Angle180) + assertEquals(Angle.Angle90 * 10.0, Angle.Angle180) + assertEquals(Angle.Angle180 * 0.5, Angle.Angle90) + assertEquals(Angle.Angle90 * 40000000.0, Angle.Angle0) + assert(((Angle.Angle180 * 0.001) - Angle.fromDoubleDegrees(0.18)).toMicroarcseconds < 1000) + assert(((Angle.Angle180 * -0.001) - Angle.fromDoubleDegrees(359.82)).toMicroarcseconds < 1000) + } }