diff --git a/shared/src/main/scala/squants/Quantity.scala b/shared/src/main/scala/squants/Quantity.scala index ab276823..76cf8b72 100644 --- a/shared/src/main/scala/squants/Quantity.scala +++ b/shared/src/main/scala/squants/Quantity.scala @@ -308,8 +308,3 @@ abstract class Quantity[A <: Quantity[A]] extends Serializable with Ordered[A] { def map(f: Double ⇒ Double): A = unit(f(value)) } -abstract class StrictlyPositiveQuantity[A <: StrictlyPositiveQuantity[A]](value: Double) extends Quantity[A] {self: A ⇒ - if(value < 0) { - throw new IllegalArgumentException("Cannot create negative StrictlyPositiveQuantity") - } -} diff --git a/shared/src/main/scala/squants/mass/Mass.scala b/shared/src/main/scala/squants/mass/Mass.scala index 0b206d6d..07e5f8b6 100644 --- a/shared/src/main/scala/squants/mass/Mass.scala +++ b/shared/src/main/scala/squants/mass/Mass.scala @@ -39,6 +39,14 @@ final class Mass private (val value: Double, val unit: MassUnit) def /(that: AreaDensity): Area = SquareMeters(toKilograms / that.toKilogramsPerSquareMeter) def /(that: Area): AreaDensity = KilogramsPerSquareMeter(toKilograms / that.toSquareMeters) + /** + * Moment of inertia of a point mass with with this mass and the given + * radius from the center of rotation + * @param radius length to center of rotation + * @return moment of inertia of a point mass with given mass and radius + */ + def onRadius(radius: Length): MomentOfInertia = KilogramsMetersSquared(toKilograms * radius.squared.toSquareMeters) + def toMicrograms = to(Micrograms) def toMilligrams = to(Milligrams) def toGrams = to(Grams) diff --git a/shared/src/main/scala/squants/mass/MomentOfIntertia.scala b/shared/src/main/scala/squants/mass/MomentOfIntertia.scala index 63431902..10da6fce 100644 --- a/shared/src/main/scala/squants/mass/MomentOfIntertia.scala +++ b/shared/src/main/scala/squants/mass/MomentOfIntertia.scala @@ -2,7 +2,7 @@ package squants.mass import squants.motion.{AngularAcceleration, NewtonMeters, Torque} import squants.space.{Feet, Meters} -import squants.{Dimension, PrimaryUnit, SiBaseUnit, StrictlyPositiveQuantity, UnitConverter, UnitOfMeasure} +import squants.{AbstractQuantityNumeric, Dimension, Length, PrimaryUnit, Quantity, SiBaseUnit, UnitConverter, UnitOfMeasure} /** * @@ -12,7 +12,7 @@ import squants.{Dimension, PrimaryUnit, SiBaseUnit, StrictlyPositiveQuantity, Un * @param value Double */ final class MomentOfInertia private (val value: Double, val unit: MomentOfInertiaUnit) - extends StrictlyPositiveQuantity[MomentOfInertia](value){ + extends Quantity[MomentOfInertia]{ def dimension = MomentOfInertia @@ -20,10 +20,19 @@ final class MomentOfInertia private (val value: Double, val unit: MomentOfInerti def toPoundsSquareFeet = to(PoundsSquareFeet) def *(angularAcceleration: AngularAcceleration): Torque = { - val kilogramsMetersSquared = toKilogramsMetersSquared val radiansPerSecondSquared = angularAcceleration.toRadiansPerSecondSquared - NewtonMeters(kilogramsMetersSquared * radiansPerSecondSquared) + NewtonMeters(toKilogramsMetersSquared * radiansPerSecondSquared) + } + + /** + * For a point mass with the given MomentOfInertia rotating with a center of + * rotation at the given radius, return the mass of the point mass + * @param radius distance to axis of rotation + * @return mass of point mass with given radius and MomentOfInertia + */ + def atCenter(radius: Length): Mass = { + Kilograms(toKilogramsMetersSquared / radius.squared.toSquareMeters) } } @@ -49,4 +58,16 @@ object KilogramsMetersSquared extends MomentOfInertiaUnit with PrimaryUnit with object PoundsSquareFeet extends MomentOfInertiaUnit { val symbol = Pounds.symbol + "‧" + Feet.symbol + "²" val conversionFactor = Pounds.conversionFactor * math.pow(Feet.conversionFactor, 2D) +} + +object MomentOfInertiaConversions { + lazy val kilogramMetersSquared = KilogramsMetersSquared(1) + lazy val poundSquareFeet = PoundsSquareFeet(1) + + implicit class MomentOfInertiaConversions[A](val n: A) extends AnyVal { + def kilogramMetersSquared(implicit num: Numeric[A]) = KilogramsMetersSquared(n) + def poundSquareFeet(implicit num: Numeric[A]) = PoundsSquareFeet(n) + } + + implicit object MomentOfInertiaNumeric extends AbstractQuantityNumeric[MomentOfInertia](MomentOfInertia.primaryUnit) } \ No newline at end of file diff --git a/shared/src/main/scala/squants/motion/AngularAcceleration.scala b/shared/src/main/scala/squants/motion/AngularAcceleration.scala index 90776387..540c5c6d 100644 --- a/shared/src/main/scala/squants/motion/AngularAcceleration.scala +++ b/shared/src/main/scala/squants/motion/AngularAcceleration.scala @@ -3,7 +3,7 @@ package squants.motion import squants.mass.MomentOfInertia import squants.space._ import squants.time.{Seconds, Time, TimeDerivative} -import squants.{Dimension, Length, PrimaryUnit, Quantity, SiUnit, UnitConverter, UnitOfMeasure} +import squants.{AbstractQuantityNumeric, Dimension, Length, PrimaryUnit, Quantity, SiUnit, UnitConverter, UnitOfMeasure} /** * @@ -18,10 +18,20 @@ final class AngularAcceleration private (val value: Double, val unit: AngularAcc def dimension = AngularAcceleration def toRadiansPerSecondSquared = to(RadiansPerSecondSquared) + def toDegreesPerSecondSquared = to(DegreesPerSecondSquared) + def toGradsPerSecondSquared = to(GradiansPerSecondSquared) + def toTurnsPerSecondSquared = to(TurnsPerSecondSquared) + def toArcminutesPerSecondSquared = to(ArcminutesPerSecondSquared) + def toArcsecondsPerSecondSquared = to(ArcsecondsPerSecondSquared) + + /** + * linear acceleration of an object rotating with this angular acceleration + * and the given radius from the center of rotation + * @param radius the distance from the center of rotation + * @return linear acceleration with given angular acceleration and radius + */ + def onRadius(radius: Length): Acceleration = toRadiansPerSecondSquared * radius / Seconds(1).squared - def onRadius(that: Length): Acceleration = { - toRadiansPerSecondSquared * that / Seconds(1).squared - } def *(that: MomentOfInertia): Torque = { NewtonMeters(toRadiansPerSecondSquared * that.toKilogramsMetersSquared) @@ -32,7 +42,6 @@ final class AngularAcceleration private (val value: Double, val unit: AngularAcc override protected[squants] def time: Time = Seconds(1) } - object AngularAcceleration extends Dimension[AngularAcceleration] { private[motion] def apply[A](n: A, unit: AngularAccelerationUnit)(implicit num: Numeric[A]) = new AngularAcceleration(num.toDouble(n), unit) def apply = parse _ @@ -58,11 +67,11 @@ trait AngularAccelerationUnit extends UnitOfMeasure[AngularAcceleration] with } object RadiansPerSecondSquared extends AngularAccelerationUnit with PrimaryUnit with SiUnit{ - override val symbol: String = "rad/s²" + val symbol = Radians.symbol + "/s²" } object DegreesPerSecondSquared extends AngularAccelerationUnit { - val symbol = "°/s²" + val symbol = Degrees.symbol + "/s²" val conversionFactor = Degrees.conversionFactor } @@ -84,4 +93,20 @@ object ArcminutesPerSecondSquared extends AngularAccelerationUnit { object ArcsecondsPerSecondSquared extends AngularAccelerationUnit{ val symbol = Arcseconds.symbol + "/s²" val conversionFactor = Arcseconds.conversionFactor +} + +object AngularAccelerationConversions { + lazy val radianPerSecondSquared = RadiansPerSecondSquared(1) + lazy val degreePerSecondSquared = DegreesPerSecondSquared(1) + lazy val gradPerSecondSquared = GradiansPerSecondSquared(1) + lazy val turnPerSecondSquared = TurnsPerSecondSquared(1) + + implicit class AngularAccelerationConversions[A](val n: A) extends AnyVal { + def radiansPerSecondSquared(implicit num: Numeric[A]) = RadiansPerSecondSquared(n) + def degreesPerSecondSquared(implicit num: Numeric[A]) = DegreesPerSecondSquared(n) + def gradsPerSecondSquared(implicit num: Numeric[A]) = GradiansPerSecondSquared(n) + def turnsPerSecondSquared(implicit num: Numeric[A]) = TurnsPerSecondSquared(n) + } + + implicit object AngularAccelerationNumeric extends AbstractQuantityNumeric[AngularAcceleration](AngularAcceleration.primaryUnit) } \ No newline at end of file diff --git a/shared/src/main/scala/squants/motion/AngularVelocity.scala b/shared/src/main/scala/squants/motion/AngularVelocity.scala index 08172832..7557adbb 100644 --- a/shared/src/main/scala/squants/motion/AngularVelocity.scala +++ b/shared/src/main/scala/squants/motion/AngularVelocity.scala @@ -25,12 +25,18 @@ final class AngularVelocity private (val value: Double, val unit: AngularVelocit def toRadiansPerSecond = to(RadiansPerSecond) def toDegreesPerSecond = to(DegreesPerSecond) - def toGradsPerSecond = to(GradsPerSecond) + @deprecated(message = "Potentially confusing naming. Use toGradiansPerSecond instead.", since = "Squants 1.2") + def toGradsPerSecond = to(GradiansPerSecond) + def toGradiansPerSecond = to(GradiansPerSecond) def toTurnsPerSecond = to(TurnsPerSecond) - def onRadius(that: Length): Velocity = { - toRadiansPerSecond * that / Seconds(1) - } + /** + * linear velocity of an object rotating with this angular velocity + * and the given radius from the center of rotation + * @param radius the distance from the center of rotation + * @return linear velocity with given angular velocity and radius + */ + def onRadius(radius: Length): Velocity = toRadiansPerSecond * radius / Seconds(1) protected[squants] def timeIntegrated: Angle = Radians(toRadiansPerSecond) @@ -45,7 +51,7 @@ object AngularVelocity extends Dimension[AngularVelocity] { def name = "AngularVelocity" def primaryUnit = RadiansPerSecond def siUnit = RadiansPerSecond - def units = Set(RadiansPerSecond, DegreesPerSecond, GradsPerSecond, TurnsPerSecond) + def units = Set(RadiansPerSecond, DegreesPerSecond, GradiansPerSecond, TurnsPerSecond) } trait AngularVelocityUnit extends UnitOfMeasure[AngularVelocity] with UnitConverter { @@ -61,6 +67,12 @@ object DegreesPerSecond extends AngularVelocityUnit { val conversionFactor = Degrees.conversionFactor * Radians.conversionFactor } +object GradiansPerSecond extends AngularVelocityUnit { + val symbol = "grad/s" + val conversionFactor = Gradians.conversionFactor * Radians.conversionFactor +} + +@deprecated(message = "Potentially confusing naming. Use GradiansPerSecond instead.", since = "Squants 1.2") object GradsPerSecond extends AngularVelocityUnit { val symbol = "grad/s" val conversionFactor = Gradians.conversionFactor * Radians.conversionFactor @@ -74,13 +86,16 @@ object TurnsPerSecond extends AngularVelocityUnit { object AngularVelocityConversions { lazy val radianPerSecond = RadiansPerSecond(1) lazy val degreePerSecond = DegreesPerSecond(1) - lazy val gradPerSecond = GradsPerSecond(1) + lazy val gradPerSecond = GradiansPerSecond(1) + lazy val gradiansPerSecond = GradiansPerSecond(1) lazy val turnPerSecond = TurnsPerSecond(1) implicit class AngularVelocityConversions[A](n: A)(implicit num: Numeric[A]) { def radiansPerSecond = RadiansPerSecond(n) def degreesPerSecond = DegreesPerSecond(n) - def gradsPerSecond = GradsPerSecond(n) + @deprecated(message = "Potentially confusing naming. Use gradiansPerSecond instead.", since = "Squants 1.2") + def gradsPerSecond = GradiansPerSecond(n) + def gradiansPerSecond = GradiansPerSecond(n) def turnsPerSecond = TurnsPerSecond(n) } diff --git a/shared/src/main/scala/squants/motion/Torque.scala b/shared/src/main/scala/squants/motion/Torque.scala index ae733710..94260245 100644 --- a/shared/src/main/scala/squants/motion/Torque.scala +++ b/shared/src/main/scala/squants/motion/Torque.scala @@ -1,8 +1,8 @@ package squants.motion -import squants.mass.{MomentOfInertia, Pounds} +import squants.mass.{Kilograms, MomentOfInertia, Pounds} import squants.space.{Feet, Meters} -import squants.{Dimension, Energy, PrimaryUnit, Quantity, SiBaseUnit, UnitConverter, UnitOfMeasure} +import squants.{AbstractQuantityNumeric, Dimension, Energy, PrimaryUnit, Quantity, SiBaseUnit, UnitConverter, UnitOfMeasure} /** * @@ -17,6 +17,7 @@ final class Torque private (val value: Double, val unit: TorqueUnit) def dimension = Torque def toNewtonMeters = to(NewtonMeters) + def toPoundFeet = to(PoundFeet) def / (that: MomentOfInertia): AngularAcceleration = { RadiansPerSecondSquared(toNewtonMeters / that.toKilogramsMetersSquared) @@ -26,7 +27,7 @@ final class Torque private (val value: Double, val unit: TorqueUnit) object Torque extends Dimension[Torque] { private[motion] def apply[A](n: A, unit: TorqueUnit)(implicit num: Numeric[A]) = new Torque(num.toDouble(n), unit) def apply = parse _ - def name = "MomentOfInertia" + def name = "Torque" def primaryUnit = NewtonMeters def siUnit = NewtonMeters def units = Set(NewtonMeters, PoundFeet) @@ -44,5 +45,17 @@ object NewtonMeters extends TorqueUnit with PrimaryUnit with SiBaseUnit { object PoundFeet extends TorqueUnit { val symbol = Pounds.symbol + "‧" + Feet.symbol - val conversionFactor = Pounds.conversionFactor * Feet.conversionFactor + val conversionFactor = PoundForce.conversionFactor * Feet.conversionFactor +} + +object TorqueConversions { + lazy val newtonMeters = NewtonMeters(1) + lazy val poundFeet = PoundFeet(1) + + implicit class TorqueConversions[A](val n: A) extends AnyVal { + def newtonMeters(implicit num: Numeric[A]) = NewtonMeters(n) + def poundFeet(implicit num: Numeric[A]) = PoundFeet(n) + } + + implicit object TorqueNumeric extends AbstractQuantityNumeric[Torque](Torque.primaryUnit) } \ No newline at end of file diff --git a/shared/src/main/scala/squants/space/Angle.scala b/shared/src/main/scala/squants/space/Angle.scala index 25d2e3a1..8dce07cb 100644 --- a/shared/src/main/scala/squants/space/Angle.scala +++ b/shared/src/main/scala/squants/space/Angle.scala @@ -36,9 +36,15 @@ final class Angle private (val value: Double, val unit: AngleUnit) def asin = math.asin(toRadians) def acos = math.acos(toRadians) - def onRadius(that: Length): Length = { - toRadians * that - } + /** + * length of the arc traveled by a point on the rim of a circle with this + * angle traveled and the given (constant) radius from the center of + * rotation + * @param radius the distance from the center of rotation + * @return arc length with given arc measure and radius + */ + def onRadius(radius: Length): Length = toRadians * radius + protected def timeDerived: AngularVelocity = RadiansPerSecond(toRadians) diff --git a/shared/src/test/scala/squants/mass/MassSpec.scala b/shared/src/test/scala/squants/mass/MassSpec.scala index 0797886e..d34c82db 100644 --- a/shared/src/test/scala/squants/mass/MassSpec.scala +++ b/shared/src/test/scala/squants/mass/MassSpec.scala @@ -8,11 +8,11 @@ package squants.mass -import org.scalatest.{ FlatSpec, Matchers } +import org.scalatest.{FlatSpec, Matchers} import squants.motion._ -import squants.space.{ CubicMeters, SquareMeters } +import squants.space.{CubicMeters, Meters, SquareMeters} import squants.time.Seconds -import squants.{ MetricSystem, QuantityParseException } +import squants.{MetricSystem, QuantityParseException} /** * @author garyKeorkunian @@ -147,6 +147,10 @@ class MassSpec extends FlatSpec with Matchers { Kilograms(1) / KilogramsPerSquareMeter(1) should be(SquareMeters(1)) } + it should "return MomentOfInertia when onRadius of Length" in { + Kilograms(1) onRadius Meters(1) should be(KilogramsMetersSquared(1)) + } + behavior of "MassConversions" it should "provide aliases for single unit values" in { diff --git a/shared/src/test/scala/squants/mass/MomentOfInertiaSpec.scala b/shared/src/test/scala/squants/mass/MomentOfInertiaSpec.scala new file mode 100644 index 00000000..5cfcb96d --- /dev/null +++ b/shared/src/test/scala/squants/mass/MomentOfInertiaSpec.scala @@ -0,0 +1,77 @@ +package squants.mass + +import org.scalatest.{FlatSpec, Matchers} +import squants.CustomMatchers +import squants.motion.{AngularAccelerationConversions, NewtonMeters, RadiansPerSecondSquared} +import squants.space.{Feet, Meters} + +/** + * + * @author paxelord + * @since 1.2 + **/ +class MomentOfInertiaSpec extends FlatSpec with Matchers with CustomMatchers { + + behavior of "MomentOfInertia and its Units of Measure" + + val unitValueSi = KilogramsMetersSquared(1) + + it should "create values using UOM factories" in { + KilogramsMetersSquared(10.22).toKilogramsMetersSquared should be(10.22) + PoundsSquareFeet(10.22).toPoundsSquareFeet should be(10.22) + } + + it should "create values from properly formatted Strings" in { + MomentOfInertia("10.22 kg‧m²").get should be(KilogramsMetersSquared(10.22)) + MomentOfInertia("10.22 lb‧ft²").get should be(PoundsSquareFeet(10.22)) + } + + it should "properly convert to all supported Units of Measure" in { + implicit val tolerance = 1e-10 + val a = KilogramsMetersSquared(1) + + val kilogramsToPounds = 1D / Pounds.conversionFactor + val metersToFeet = 1D / Feet.conversionFactor + a.toPoundsSquareFeet should beApproximately(kilogramsToPounds * metersToFeet * metersToFeet) + + val b = PoundsSquareFeet(1) + val poundsToKilograms = Pounds.conversionFactor + val feetToMeters = Feet.conversionFactor + b.toKilogramsMetersSquared should beApproximately(poundsToKilograms * feetToMeters * feetToMeters) + } + + it should "return properly formatted strings for all supported Units of Measure" in { + PoundsSquareFeet(1).toString(PoundsSquareFeet) should be("1.0 lb‧ft²") + unitValueSi.toString(KilogramsMetersSquared) should be("1.0 kg‧m²") + } + + it should "return Torque when multiplied by AngularAcceleration" in { + unitValueSi * RadiansPerSecondSquared(1) should be(NewtonMeters(1)) + } + + it should "return mass when atCenter is called" in { + unitValueSi atCenter Meters(1) should be(Kilograms(1)) + } + + it should "provide aliases for single unit values" in { + import MomentOfInertiaConversions._ + + poundSquareFeet should be(PoundsSquareFeet(1)) + kilogramMetersSquared should be(KilogramsMetersSquared(1)) + } + + it should "provide implicit conversion from Double" in { + import MomentOfInertiaConversions._ + + val d = 10.22 + d.kilogramMetersSquared should be(KilogramsMetersSquared(d)) + d.poundSquareFeet should be(PoundsSquareFeet(d)) + } + + it should "provide Numeric support" in { + import MomentOfInertiaConversions._ + + val momentOfInertiaList = List(KilogramsMetersSquared(100), KilogramsMetersSquared(10)) + momentOfInertiaList.sum should be(KilogramsMetersSquared(110)) + } +} diff --git a/shared/src/test/scala/squants/motion/AngularAccelerationSpec.scala b/shared/src/test/scala/squants/motion/AngularAccelerationSpec.scala new file mode 100644 index 00000000..b0e7db58 --- /dev/null +++ b/shared/src/test/scala/squants/motion/AngularAccelerationSpec.scala @@ -0,0 +1,83 @@ +package squants.motion + +import org.scalatest.{FlatSpec, Matchers} +import squants.QuantityParseException +import squants.space.{Meters, Radians} +import squants.time.Seconds + +/** + * + * @author paxelord + * @since 1.2 + */ +class AngularAccelerationSpec extends FlatSpec with Matchers{ + + behavior of "AngularAcceleration and its Units of Measure" + + it should "create values using UOM factories" in { + RadiansPerSecondSquared(1).toRadiansPerSecondSquared should be(1) + DegreesPerSecondSquared(1).toDegreesPerSecondSquared should be(1) + GradiansPerSecondSquared(1).toGradsPerSecondSquared should be(1) + TurnsPerSecondSquared(1).toTurnsPerSecondSquared should be(1) + } + + it should "create values from properly formatted Strings" in { + AngularAcceleration("10.22 rad/s²").get should be(RadiansPerSecondSquared(10.22)) + AngularAcceleration("10.22 °/s²").get should be(DegreesPerSecondSquared(10.22)) + AngularAcceleration("10.22 grad/s²").get should be(GradiansPerSecondSquared(10.22)) + AngularAcceleration("10.22 turns/s²").get should be(TurnsPerSecondSquared(10.22)) + AngularAcceleration("10.22 zz").failed.get should be(QuantityParseException("Unable to parse AngularAcceleration", "10.22 zz")) + AngularAcceleration("zz rad/s²").failed.get should be(QuantityParseException("Unable to parse AngularAcceleration", "zz rad/s²")) + } + + it should "properly convert to all supported Units of Measure" in { + val x = RadiansPerSecondSquared(1) + x.toRadiansPerSecondSquared should be(1) + x.toDegreesPerSecondSquared should be(Radians(1).toDegrees) + x.toGradsPerSecondSquared should be(Radians(1).toGradians) + x.toTurnsPerSecondSquared should be(Radians(1).toTurns) + } + + it should "return properly formatted strings for all supported Units of Measure" in { + RadiansPerSecondSquared(1).toString(RadiansPerSecondSquared) should be("1.0 rad/s²") + DegreesPerSecondSquared(1).toString(DegreesPerSecondSquared) should be("1.0 °/s²") + GradiansPerSecondSquared(1).toString(GradiansPerSecondSquared) should be("1.0 grad/s²") + TurnsPerSecondSquared(1).toString(TurnsPerSecondSquared) should be("1.0 turns/s²") + } + + it should "return AnglularVelocity when multiplied by Time" in { + RadiansPerSecondSquared(1) * Seconds(1) should be(RadiansPerSecond(1)) + } + + it should "return Acceleration of particle onRadius of AngularAcceleration" in { + RadiansPerSecondSquared(1) onRadius Meters(1) should be(MetersPerSecondSquared(1)) + } + + behavior of "AngularAccelerationConversions" + + it should "provide aliases for single unit values" in { + import AngularAccelerationConversions._ + + radianPerSecondSquared should be(RadiansPerSecondSquared(1)) + degreePerSecondSquared should be(DegreesPerSecondSquared(1)) + gradPerSecondSquared should be(GradiansPerSecondSquared(1)) + turnPerSecondSquared should be(TurnsPerSecondSquared(1)) + } + + it should "provide implicit conversion from Double" in { + import AngularAccelerationConversions._ + + val d = 10.22d + d.radiansPerSecondSquared should be(RadiansPerSecondSquared(d)) + d.degreesPerSecondSquared should be(DegreesPerSecondSquared(d)) + d.gradsPerSecondSquared should be(GradiansPerSecondSquared(d)) + d.turnsPerSecondSquared should be(TurnsPerSecondSquared(d)) + } + + it should "provide Numeric support" in { + import AngularAccelerationConversions.AngularAccelerationNumeric + + val aas = List(RadiansPerSecondSquared(100), RadiansPerSecondSquared(10)) + aas.sum should be(RadiansPerSecondSquared(110)) + } +} diff --git a/shared/src/test/scala/squants/motion/AngularVelocitySpec.scala b/shared/src/test/scala/squants/motion/AngularVelocitySpec.scala index adef7e4e..7425300f 100644 --- a/shared/src/test/scala/squants/motion/AngularVelocitySpec.scala +++ b/shared/src/test/scala/squants/motion/AngularVelocitySpec.scala @@ -8,8 +8,8 @@ package squants.motion -import org.scalatest.{ Matchers, FlatSpec } -import squants.space.Radians +import org.scalatest.{FlatSpec, Matchers} +import squants.space.{Meters, Radians} import squants.QuantityParseException import squants.time.Seconds @@ -25,14 +25,15 @@ class AngularVelocitySpec extends FlatSpec with Matchers { it should "create values using UOM factories" in { RadiansPerSecond(1).toRadiansPerSecond should be(1) DegreesPerSecond(1).toDegreesPerSecond should be(1) - GradsPerSecond(1).toGradsPerSecond should be(1) + GradiansPerSecond(1).toGradiansPerSecond should be(1) + GradiansPerSecond(1).toGradsPerSecond should be(1) TurnsPerSecond(1).toTurnsPerSecond should be(1) } it should "create values from properly formatted Strings" in { AngularVelocity("10.22 rad/s").get should be(RadiansPerSecond(10.22)) AngularVelocity("10.22 °/s").get should be(DegreesPerSecond(10.22)) - AngularVelocity("10.22 grad/s").get should be(GradsPerSecond(10.22)) + AngularVelocity("10.22 grad/s").get should be(GradiansPerSecond(10.22)) AngularVelocity("10.22 turns/s").get should be(TurnsPerSecond(10.22)) AngularVelocity("10.22 zz").failed.get should be(QuantityParseException("Unable to parse AngularVelocity", "10.22 zz")) AngularVelocity("zz rad/s").failed.get should be(QuantityParseException("Unable to parse AngularVelocity", "zz rad/s")) @@ -43,13 +44,14 @@ class AngularVelocitySpec extends FlatSpec with Matchers { x.toRadiansPerSecond should be(1) x.toDegreesPerSecond should be(Radians(1).toDegrees) x.toGradsPerSecond should be(Radians(1).toGradians) + x.toGradiansPerSecond should be(Radians(1).toGradians) x.toTurnsPerSecond should be(Radians(1).toTurns) } it should "return properly formatted strings for all supported Units of Measure" in { RadiansPerSecond(1).toString(RadiansPerSecond) should be("1.0 rad/s") DegreesPerSecond(1).toString(DegreesPerSecond) should be("1.0 °/s") - GradsPerSecond(1).toString(GradsPerSecond) should be("1.0 grad/s") + GradiansPerSecond(1).toString(GradiansPerSecond) should be("1.0 grad/s") TurnsPerSecond(1).toString(TurnsPerSecond) should be("1.0 turns/s") } @@ -57,7 +59,13 @@ class AngularVelocitySpec extends FlatSpec with Matchers { RadiansPerSecond(1) * Seconds(1) should be(Radians(1)) } -// it should "" + it should "return AngularAcceleration when divided by Time" in { + RadiansPerSecond(1) / Seconds(1) should be(RadiansPerSecondSquared(1)) + } + + it should "return Velocity of particle onRadius of AngularVelocity" in { + RadiansPerSecond(1) onRadius Meters(1) should be(MetersPerSecond(1)) + } behavior of "AngularVelocityConversions" @@ -66,7 +74,8 @@ class AngularVelocitySpec extends FlatSpec with Matchers { radianPerSecond should be(RadiansPerSecond(1)) degreePerSecond should be(DegreesPerSecond(1)) - gradPerSecond should be(GradsPerSecond(1)) + gradPerSecond should be(GradiansPerSecond(1)) + gradiansPerSecond should be(GradiansPerSecond(1)) turnPerSecond should be(TurnsPerSecond(1)) } @@ -76,7 +85,8 @@ class AngularVelocitySpec extends FlatSpec with Matchers { val d = 10.22d d.radiansPerSecond should be(RadiansPerSecond(d)) d.degreesPerSecond should be(DegreesPerSecond(d)) - d.gradsPerSecond should be(GradsPerSecond(d)) + d.gradsPerSecond should be(GradiansPerSecond(d)) + d.gradiansPerSecond should be(GradiansPerSecond(d)) d.turnsPerSecond should be(TurnsPerSecond(d)) } diff --git a/shared/src/test/scala/squants/motion/TorqueSpec.scala b/shared/src/test/scala/squants/motion/TorqueSpec.scala new file mode 100644 index 00000000..b8c4a6e3 --- /dev/null +++ b/shared/src/test/scala/squants/motion/TorqueSpec.scala @@ -0,0 +1,67 @@ +package squants.motion + +import org.scalatest.{FlatSpec, Matchers} +import squants.{CustomMatchers, QuantityParseException} +import squants.mass.{KilogramsMetersSquared, PoundsSquareFeet} +import squants.space.{Feet, Meters} + +/** + * + * @author paxelord + * @since 1.2 + */ +class TorqueSpec extends FlatSpec with Matchers with CustomMatchers { + + behavior of "Torque and its Units of Measure" + + it should "create values using UOM factories" in { + NewtonMeters(1).toNewtonMeters should be(1) + PoundsSquareFeet(1).toPoundsSquareFeet should be(1) + } + + it should "create values from properly formatted Strings" in { + Torque("10.22 N‧m").get should be(NewtonMeters(10.22)) + Torque("10.22 lb‧ft").get should be(PoundFeet(10.22)) + Torque("10.22 zz").failed.get should be(QuantityParseException("Unable to parse Torque", "10.22 zz")) + Torque("zz N‧m").failed.get should be(QuantityParseException("Unable to parse Torque", "zz N‧m")) + } + + it should "properly convert to all supported Units of Measure" in { + implicit val tolerance = 1e-10 + NewtonMeters(1).toPoundFeet should beApproximately(Newtons(1).toPoundForce * Meters(1).toFeet) + PoundFeet(1).toNewtonMeters should beApproximately(PoundForce(1).toNewtons * Feet(1).toMeters) + } + + it should "return properly formatted strings for all supported Units of Measure" in { + NewtonMeters(1).toString(NewtonMeters) should be("1.0 N‧m") + PoundFeet(1).toString(PoundFeet) should be("1.0 lb‧ft") + } + + it should "return AngularAcceleration when divided by MomentOfInertia" in { + NewtonMeters(1) / KilogramsMetersSquared(1) should be(RadiansPerSecondSquared(1)) + } + + behavior of "TorqueConversions" + + it should "provide aliases for single unit values" in { + import TorqueConversions._ + + newtonMeters should be(NewtonMeters(1)) + poundFeet should be(PoundFeet(1)) + } + + it should "provide implicit conversion from Double" in { + import TorqueConversions._ + + val d = 10d + d.newtonMeters should be(NewtonMeters(d)) + d.poundFeet should be(PoundFeet(d)) + } + + it should "provide Numeric support" in { + import TorqueConversions.TorqueNumeric + + val torqueList = List(NewtonMeters(100), NewtonMeters(10)) + torqueList.sum should be(NewtonMeters(110)) + } +} \ No newline at end of file