diff --git a/AUTHORS b/AUTHORS index a18cb0c..648a164 100644 --- a/AUTHORS +++ b/AUTHORS @@ -4,3 +4,4 @@ add your name to the end of this list! Ian Mackenzie Matthias Devlamynck +Katja Mordaunt diff --git a/elm.json b/elm.json index 4cf8948..a4fe4c7 100644 --- a/elm.json +++ b/elm.json @@ -22,7 +22,8 @@ "Resistance", "Speed", "Temperature", - "Voltage" + "Voltage", + "Volume" ], "elm-version": "0.19.0 <= v < 0.20.0", "dependencies": { diff --git a/src/Quantity.elm b/src/Quantity.elm index f9f59a8..eb3cac4 100644 --- a/src/Quantity.elm +++ b/src/Quantity.elm @@ -1,9 +1,9 @@ module Quantity exposing ( Quantity(..) - , Squared, Rate + , Squared, Cubed, Rate , zero, infinity, positiveInfinity, negativeInfinity , lessThan, greaterThan, compare, equalWithin, max, min, isNaN, isInfinite - , negate, plus, minus, product, ratio, scaleBy, divideBy, abs, clamp, squared, sqrt + , negate, plus, minus, product, ratio, scaleBy, divideBy, abs, clamp, squared, sqrt, cubed, cbrt , round, floor, ceiling, truncate, toFloatQuantity , sum, minimum, maximum, sort , per, times, at, at_, inverse @@ -17,10 +17,10 @@ module Quantity exposing # Unit types -The `Squared` and `Rate` units types allow you to build up and work with +The `Squared`, `Cubed` and `Rate` units types allow you to build up and work with composite units in a fairly flexible way. -@docs Squared, Rate +@docs Squared, Cubed, Rate # Constants @@ -35,7 +35,7 @@ composite units in a fairly flexible way. # Arithmetic -@docs negate, plus, minus, product, ratio, scaleBy, divideBy, abs, clamp, squared, sqrt +@docs negate, plus, minus, product, ratio, scaleBy, divideBy, abs, clamp, squared, sqrt, cubed, cbrt # `Int`/`Float` conversion @@ -111,6 +111,17 @@ type Squared units = Squared units +{-| Represents a units type that is the cube of some other units type; for +example, `Meters` is one units type (the units type of a `Length`) and `Cubed +Meters` is another (the units type of an `Volume`). This is useful because some +functions in this module (specifically [`cubed`](Quantity#cubed) +and [`cbrt`](Quantity#cbrt)) "know" about the +`Cubed` type and how to work with it. +-} +type Cubed units + = Cubed units + + {-| Represents the units type of a rate or quotient such as a speed (`Rate Meters Seconds`) or a pressure (`Rate Newtons SquareMeters`). As with `Squared`, there are several functions that "know" about the `Rate` units type and how to @@ -504,6 +515,26 @@ sqrt (Quantity value) = Quantity (Basics.sqrt value) +{-| Cube a quantity with some `units`, resulting in a new quantity in +`Cubed units`. +-} +cubed : Quantity number units -> Quantity number (Cubed units) +cubed (Quantity value) = + Quantity (value * value * value) + + +{-| Take a quantity in `Cubed units` and return the cube root of that +quantity in plain `units`. +-} +cbrt : Quantity Float (Cubed units) -> Quantity Float units +cbrt (Quantity value) = + if value >= 0 then + Quantity (value ^ (1 / 3)) + + else + Quantity -(-value ^ (1 / 3)) + + ---------- INT/FLOAT CONVERSIONS ---------- diff --git a/src/Volume.elm b/src/Volume.elm new file mode 100644 index 0000000..ef41388 --- /dev/null +++ b/src/Volume.elm @@ -0,0 +1,313 @@ +module Volume exposing + ( Volume, CubicMeters + , cubicMeters, inCubicMeters + , milliliters, inMilliliters, liters, inLiters + , cubicInches, inCubicInches, cubicFeet, inCubicFeet, cubicYards, inCubicYards + , usLiquidGallons, inUsLiquidGallons, usDryGallons, inUsDryGallons, imperialGallons, inImperialGallons + , usLiquidQuarts, inUsLiquidQuarts, usDryQuarts, inUsDryQuarts, imperialQuarts, inImperialQuarts + , usLiquidPints, inUsLiquidPints, usDryPints, inUsDryPints, imperialPints, inImperialPints + , usFluidOunces, inUsFluidOunces, imperialFluidOunces, inImperialFluidOunces + ) + +{-| A `Volume` represents a volume in cubic meters, cubic feet, liters, US +liquid gallons, imperial fluid ounces etc. It is stored as a number of cubic +meters. + +@docs Volume, CubicMeters + + +## Metric + +@docs cubicMeters, inCubicMeters +@docs milliliters, inMilliliters, liters, inLiters + + +## Imperial + +@docs cubicInches, inCubicInches, cubicFeet, inCubicFeet, cubicYards, inCubicYards +@docs usLiquidGallons, inUsLiquidGallons, usDryGallons, inUsDryGallons, imperialGallons, inImperialGallons +@docs usLiquidQuarts, inUsLiquidQuarts, usDryQuarts, inUsDryQuarts, imperialQuarts, inImperialQuarts +@docs usLiquidPints, inUsLiquidPints, usDryPints, inUsDryPints, imperialPints, inImperialPints +@docs usFluidOunces, inUsFluidOunces, imperialFluidOunces, inImperialFluidOunces + +-} + +import Length exposing (Meters) +import Quantity exposing (Cubed, Quantity(..)) + + +{-| -} +type alias CubicMeters = + Cubed Meters + + +{-| -} +type alias Volume = + Quantity Float CubicMeters + + + +---------- CONVERSION FACTOR CONSTANTS ----------- + + +{-| The number of US liquid gallons in a cubic meter. +-} +usLiquidGallonsPerCubicMeter : Float +usLiquidGallonsPerCubicMeter = + 264.17220000000003 + + +{-| The number of US dry gallons in a cubic meter. +-} +usDryGallonsPerCubicMeter : Float +usDryGallonsPerCubicMeter = + 227.0208 + + +{-| The number of imperial gallons in a cubic meter. +-} +imperialGallonsPerCubicMeter : Float +imperialGallonsPerCubicMeter = + 219.969157 + + + +---------- CONVERSIONS ----------- + + +{-| Construct a volume from a number of cubic meters. +-} +cubicMeters : Float -> Volume +cubicMeters numCubicMeters = + Quantity numCubicMeters + + +{-| Convert a volume to a number of cubic meters. +-} +inCubicMeters : Volume -> Float +inCubicMeters (Quantity numCubicMeters) = + numCubicMeters + + +{-| Construct a volume from a number of cubic inches. +-} +cubicInches : Float -> Volume +cubicInches numCubicInches = + cubicMeters (0.0254 * 0.0254 * 0.0254 * numCubicInches) + + +{-| Convert a volume to a number of cubic inches. +-} +inCubicInches : Volume -> Float +inCubicInches volume = + inCubicMeters volume / (0.0254 * 0.0254 * 0.0254) + + +{-| Construct a volume from a number of cubic feet. +-} +cubicFeet : Float -> Volume +cubicFeet numCubicFeet = + cubicMeters (0.3048 * 0.3048 * 0.3048 * numCubicFeet) + + +{-| Convert a volume to a number of cubic feet. +-} +inCubicFeet : Volume -> Float +inCubicFeet volume = + inCubicMeters volume / (0.3048 * 0.3048 * 0.3048) + + +{-| Construct a volume from a number of cubic yards. +-} +cubicYards : Float -> Volume +cubicYards numCubicYards = + cubicMeters (0.9144 * 0.9144 * 0.9144 * numCubicYards) + + +{-| Convert a volume to a number of cubic yards. +-} +inCubicYards : Volume -> Float +inCubicYards volume = + inCubicMeters volume / (0.9144 * 0.9144 * 0.9144) + + +{-| Construct a volume from a number of milliliters. +-} +milliliters : Float -> Volume +milliliters numMilliliters = + cubicMeters (1.0e-6 * numMilliliters) + + +{-| Convert a volume to a number of milliliters. +-} +inMilliliters : Volume -> Float +inMilliliters volume = + 1.0e6 * inCubicMeters volume + + +{-| Construct a volume from a number of liters. +-} +liters : Float -> Volume +liters numLiters = + cubicMeters (0.001 * numLiters) + + +{-| Convert a volume to a number of liters. +-} +inLiters : Volume -> Float +inLiters volume = + 1000 * inCubicMeters volume + + +{-| Construct a volume from a number of U.S. liquid gallon. +-} +usLiquidGallons : Float -> Volume +usLiquidGallons numUsLiquidGallons = + cubicMeters (numUsLiquidGallons / usLiquidGallonsPerCubicMeter) + + +{-| Convert a volume to a number of U.S. liquid gallons. +-} +inUsLiquidGallons : Volume -> Float +inUsLiquidGallons volume = + usLiquidGallonsPerCubicMeter * inCubicMeters volume + + +{-| Construct a volume from a number of U.S. dry gallons. +-} +usDryGallons : Float -> Volume +usDryGallons numUsDryGallons = + cubicMeters (numUsDryGallons / usDryGallonsPerCubicMeter) + + +{-| Convert a volume to a number of U.S. dry gallons. +-} +inUsDryGallons : Volume -> Float +inUsDryGallons volume = + usDryGallonsPerCubicMeter * inCubicMeters volume + + +{-| Construct a volume from a number of imperial gallons. +-} +imperialGallons : Float -> Volume +imperialGallons numImperialGallons = + cubicMeters (numImperialGallons / imperialGallonsPerCubicMeter) + + +{-| Convert a volume to a number of imperial gallons. +-} +inImperialGallons : Volume -> Float +inImperialGallons volume = + imperialGallonsPerCubicMeter * inCubicMeters volume + + +{-| Construct a volume from a number of U.S. liquid quarts. +-} +usLiquidQuarts : Float -> Volume +usLiquidQuarts numUsLiquidQuarts = + cubicMeters ((numUsLiquidQuarts / 4) / usLiquidGallonsPerCubicMeter) + + +{-| Convert a volume to a number of U.S. liquid quarts. +-} +inUsLiquidQuarts : Volume -> Float +inUsLiquidQuarts volume = + 4 * usLiquidGallonsPerCubicMeter * inCubicMeters volume + + +{-| Construct a volume from a number of U.S. dry quarts. +-} +usDryQuarts : Float -> Volume +usDryQuarts numUsDryQuarts = + cubicMeters ((numUsDryQuarts / 4) / usDryGallonsPerCubicMeter) + + +{-| Convert a volume to a number of U.S. dry quarts. +-} +inUsDryQuarts : Volume -> Float +inUsDryQuarts volume = + 4 * usDryGallonsPerCubicMeter * inCubicMeters volume + + +{-| Construct a volume from a number of imperial quarts. +-} +imperialQuarts : Float -> Volume +imperialQuarts numImperialQuarts = + cubicMeters ((numImperialQuarts / 4) / imperialGallonsPerCubicMeter) + + +{-| Convert a volume to a number of imperial quarts. +-} +inImperialQuarts : Volume -> Float +inImperialQuarts volume = + 4 * imperialGallonsPerCubicMeter * inCubicMeters volume + + +{-| Construct a volume from a number of U.S. liquid pints. +-} +usLiquidPints : Float -> Volume +usLiquidPints numUsLiquidPints = + cubicMeters ((numUsLiquidPints / 8) / usLiquidGallonsPerCubicMeter) + + +{-| Convert a volume to a number of U.S. liquid pints. +-} +inUsLiquidPints : Volume -> Float +inUsLiquidPints volume = + 8 * usLiquidGallonsPerCubicMeter * inCubicMeters volume + + +{-| Construct a volume from a number of U.S. dry pints. +-} +usDryPints : Float -> Volume +usDryPints numUsDryPints = + cubicMeters ((numUsDryPints / 8) / usDryGallonsPerCubicMeter) + + +{-| Convert a volume to a number of U.S. dry pints. +-} +inUsDryPints : Volume -> Float +inUsDryPints volume = + 8 * usDryGallonsPerCubicMeter * inCubicMeters volume + + +{-| Construct a volume from a number of imperial pints. +-} +imperialPints : Float -> Volume +imperialPints numImperialPints = + cubicMeters ((numImperialPints / 8) / imperialGallonsPerCubicMeter) + + +{-| Convert a volume to a number of imperial pints. +-} +inImperialPints : Volume -> Float +inImperialPints volume = + 8 * imperialGallonsPerCubicMeter * inCubicMeters volume + + +{-| Construct a volume from a number of U.S. fluid ounces. +-} +usFluidOunces : Float -> Volume +usFluidOunces numUsFluidOunces = + cubicMeters ((numUsFluidOunces / 128) / usLiquidGallonsPerCubicMeter) + + +{-| Convert a volume to a number of U.S. fluid ounces. +-} +inUsFluidOunces : Volume -> Float +inUsFluidOunces volume = + 128 * usLiquidGallonsPerCubicMeter * inCubicMeters volume + + +{-| Construct a volume from a number of imperial fluid ounces. +-} +imperialFluidOunces : Float -> Volume +imperialFluidOunces numImperialFluidOunces = + cubicMeters ((numImperialFluidOunces / 160) / imperialGallonsPerCubicMeter) + + +{-| Convert a volume to a number of imperial fluid ounces. +-} +inImperialFluidOunces : Volume -> Float +inImperialFluidOunces volume = + 160 * imperialGallonsPerCubicMeter * inCubicMeters volume diff --git a/tests/Tests.elm b/tests/Tests.elm index f323dbc..24839a0 100644 --- a/tests/Tests.elm +++ b/tests/Tests.elm @@ -7,6 +7,7 @@ module Tests exposing , speeds , temperatureDeltas , temperatures + , volumes ) import Acceleration exposing (..) @@ -30,6 +31,7 @@ import Speed exposing (..) import Temperature exposing (Temperature) import Test exposing (Test) import Voltage exposing (..) +import Volume exposing (..) equalityTest : String -> String -> ( Quantity Float units, Quantity Float units ) -> Test @@ -185,6 +187,47 @@ temperatureDeltas = ] +volumes : Test +volumes = + equalPairs + "Volumes" + "m^3" + [ ( cubicMeters 2 + , usLiquidGallons (2 * 264.17220000000003) + ) + , ( imperialGallons 219.969157 + , usDryGallons 227.0208 + ) + , ( cubicInches (36 * 36 * 36) + , cubicYards 1 + ) + , ( usLiquidGallons 1 + , usLiquidQuarts 4 + ) + , ( usDryGallons 1 + , usDryQuarts 4 + ) + , ( imperialGallons 1 + , imperialQuarts 4 + ) + , ( usLiquidQuarts 1 + , usLiquidPints 2 + ) + , ( usDryQuarts 1 + , usDryPints 2 + ) + , ( imperialQuarts 1 + , imperialPints 2 + ) + , ( usLiquidPints 1 + , usFluidOunces 16 + ) + , ( imperialPints 1 + , imperialFluidOunces 20 + ) + ] + + conversionsToQuantityAndBack : Test conversionsToQuantityAndBack = Test.describe "Conversion to Quantity and back is (almost) identity" <| @@ -302,4 +345,23 @@ conversionsToQuantityAndBack = , Test.describe "Voltage" <| [ fuzzFloatToQuantityAndBack "volts" Voltage.volts Voltage.inVolts ] + , Test.describe "Volume" <| + [ fuzzFloatToQuantityAndBack "cubicMeters" Volume.cubicMeters Volume.inCubicMeters + , fuzzFloatToQuantityAndBack "cubicInches" Volume.cubicInches Volume.inCubicInches + , fuzzFloatToQuantityAndBack "cubicFeet" Volume.cubicFeet Volume.inCubicFeet + , fuzzFloatToQuantityAndBack "cubicYards" Volume.cubicYards Volume.inCubicYards + , fuzzFloatToQuantityAndBack "milliliters" Volume.milliliters Volume.inMilliliters + , fuzzFloatToQuantityAndBack "liters" Volume.liters Volume.inLiters + , fuzzFloatToQuantityAndBack "usLiquidGallons" Volume.usLiquidGallons Volume.inUsLiquidGallons + , fuzzFloatToQuantityAndBack "usDryGallons" Volume.usDryGallons Volume.inUsDryGallons + , fuzzFloatToQuantityAndBack "imperialGallons" Volume.imperialGallons Volume.inImperialGallons + , fuzzFloatToQuantityAndBack "usLiquidQuarts" Volume.usLiquidQuarts Volume.inUsLiquidQuarts + , fuzzFloatToQuantityAndBack "usDryQuarts" Volume.usDryQuarts Volume.inUsDryQuarts + , fuzzFloatToQuantityAndBack "imperialQuarts" Volume.imperialQuarts Volume.inImperialQuarts + , fuzzFloatToQuantityAndBack "usLiquidPints" Volume.usLiquidPints Volume.inUsLiquidPints + , fuzzFloatToQuantityAndBack "usDryPints" Volume.usDryPints Volume.inUsDryPints + , fuzzFloatToQuantityAndBack "imperialPints" Volume.imperialPints Volume.inImperialPints + , fuzzFloatToQuantityAndBack "usFluidOunces" Volume.usFluidOunces Volume.inUsFluidOunces + , fuzzFloatToQuantityAndBack "imperialFluidOunces" Volume.imperialFluidOunces Volume.inImperialFluidOunces + ] ]