From 383c52b759b31f0de7845e3f0a61e2169b85a01f Mon Sep 17 00:00:00 2001 From: Lukasz Drygala Date: Tue, 28 Nov 2017 15:04:46 +0100 Subject: [PATCH] Add angular unit radian --- src/main/scala/libra/nonsi/package.scala | 33 ++++++++++++++++++++--- src/main/scala/libra/ops/base.scala | 11 ++++++-- src/test/scala/libra/NonSISpec.scala | 34 +++++++++++++++++++++++- 3 files changed, 72 insertions(+), 6 deletions(-) diff --git a/src/main/scala/libra/nonsi/package.scala b/src/main/scala/libra/nonsi/package.scala index fad4963..b7a894d 100644 --- a/src/main/scala/libra/nonsi/package.scala +++ b/src/main/scala/libra/nonsi/package.scala @@ -1,9 +1,14 @@ package libra -import ops.base.{Show, ConversionFactor} -import spire._, spire.algebra._, spire.math._, spire.implicits._ +import libra.nonsi.Angle +import libra.ops.quantity.ConvertTo +import ops.base.{Conversion, ConversionFactor, Show} +import spire._ +import spire.algebra._ +import spire.math._ +import spire.implicits._ import singleton.ops._ -import libra.si.{Time, Second} +import libra.si.{Second, Time} import shapeless._ /* Non-SI units */ @@ -16,10 +21,12 @@ package object nonsi { trait Degree extends UnitOfMeasure[Angle] trait Arcminute extends UnitOfMeasure[Angle] trait Arcsecond extends UnitOfMeasure[Angle] + trait Radian extends UnitOfMeasure[Angle] implicit def degreeShow: Show[Degree] = Show[Degree]("degree") implicit def arcminuteShow: Show[Arcminute] = Show[Arcminute]("arcminute") implicit def arcsecondShow: Show[Arcsecond] = Show[Arcsecond]("arcsecond") + implicit def radian: Show[Radian] = Show[Radian]("rad") implicit def degreeArcminuteConversion[A]( implicit c: ConvertableTo[A] @@ -36,6 +43,25 @@ package object nonsi { ): ConversionFactor[A, Angle, Arcminute, Arcsecond] = new ConversionFactor(c.fromInt(60)) + implicit def radianDegreeConversion[A]( + implicit c: ConvertableTo[A] + ): ConversionFactor[A, Angle, Radian, Degree] = + new ConversionFactor(c.fromDouble(180 / pi)) + + implicit def radianArcminuteConversion[A]( + implicit c: ConvertableTo[A], + multiplicative: MultiplicativeSemigroup[A] + ): ConversionFactor[A, Angle, Radian, Arcminute] = + degreeArcminuteConversion.compose(radianDegreeConversion) + + implicit def radianArcsecondConversion[A]( + implicit c: ConvertableTo[A], + multiplicative: MultiplicativeSemigroup[A] + ): ConversionFactor[A, Angle, Radian, Arcsecond] = + degreeArcsecondConversion.compose(radianDegreeConversion) + + + type AngularVelocityQuantity[A, L <: UnitOfMeasure[Angle], T <: UnitOfMeasure[Time]] = Quantity[A, Term[Angle, L, Fraction[1, 1]] :: Term[Time, T, Fraction[-1, 1]] :: HNil] @@ -46,5 +72,6 @@ package object nonsi { def degreessPerSecond: AngularVelocityQuantity[A, Degree, Second] = Quantity(a) def arcminutesPerSecond: AngularVelocityQuantity[A, Arcminute, Second] = Quantity(a) def arcsecondsPerSecond: AngularVelocityQuantity[A, Arcsecond, Second] = Quantity(a) + def radian: QuantityOf[A, Angle, Radian] = Quantity(a) } } diff --git a/src/main/scala/libra/ops/base.scala b/src/main/scala/libra/ops/base.scala index 73ff901..618c9d0 100644 --- a/src/main/scala/libra/ops/base.scala +++ b/src/main/scala/libra/ops/base.scala @@ -1,7 +1,10 @@ package libra package ops -import spire.algebra._, spire.implicits._ +import libra.UnitOfMeasure +import spire.algebra._ +import spire.implicits._ +import spire.math.ConvertableFrom object base { @@ -23,7 +26,11 @@ object base { * @tparam F the unit to convert from * @tparam T the unit to convert to */ - case class ConversionFactor[A, D, F <: UnitOfMeasure[D], T <: UnitOfMeasure[D]](val value: A) + case class ConversionFactor[A, D, F <: UnitOfMeasure[D], T <: UnitOfMeasure[D]](val value: A) { + def compose[OtherF <: UnitOfMeasure[D]](otherConversionFactor: ConversionFactor[A, D, OtherF, F]) + (implicit multiplicativeSemigroup: MultiplicativeSemigroup[A]): ConversionFactor[A, D, OtherF, T] = + new ConversionFactor(otherConversionFactor.value * value) + } /** Derived typeclass for the conversion factor from F to T * diff --git a/src/test/scala/libra/NonSISpec.scala b/src/test/scala/libra/NonSISpec.scala index 0a67a16..28f96e6 100644 --- a/src/test/scala/libra/NonSISpec.scala +++ b/src/test/scala/libra/NonSISpec.scala @@ -1,7 +1,9 @@ package libra import spire.implicits._ -import libra.nonsi._, libra.si._ +import spire.math._ +import libra.nonsi._ +import libra.si._ import org.scalatest._ @@ -20,6 +22,10 @@ class NonSISpec extends WordSpec { "arcsecond value" in { assert(2.0.degree.to[Arcsecond].value === 7200.0) } + + "radian value" in { + assert(180.0.degree.to[Radian].value === pi) + } } "arcminute" should { @@ -76,6 +82,10 @@ class NonSISpec extends WordSpec { "arcsecond value" in { assert(2.0.arcminutesPerSecond.to[Arcsecond].value === 120.0) } + + "radian value" in { + assert(10800.0.arcminutesPerSecond.to[Radian].value === pi) + } } "arcsecondsPerSecond" should { @@ -90,5 +100,27 @@ class NonSISpec extends WordSpec { "arcminutesPerSecond value" in { assert(120.0.arcsecondsPerSecond.to[Arcminute].value === 2.0) } + + "radian value" in { + assert(648000.0.arcsecondsPerSecond.to[Radian].value === pi) + } + } + + "radians" should { + "show" in { + assert(2.radian.show === "2 rad [∠]") + } + + "degree value" in { + assert(pi.radian.to[Degree].value === 180.0) + } + + "arcminute value" in { + assert(pi.radian.to[Arcminute].value === 10800.0) + } + + "arcsecond value" in { + assert(pi.radian.to[Arcsecond].value === 648000.0) + } } }