From edcc17babd2d560950052a539d100bc169245730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20A=2E=20Michel=C3=A9n=20Str=C3=B6fer?= Date: Sun, 26 Nov 2023 18:27:01 -0700 Subject: [PATCH] working on #7 --- Project.toml | 1 + src/DimensionfulAngles.jl | 83 +++++++++++++++++++++++++++++++++++---- src/derived.jl | 2 +- src/units.jl | 8 ++-- 4 files changed, 82 insertions(+), 12 deletions(-) diff --git a/Project.toml b/Project.toml index c0e3734..edf29d1 100644 --- a/Project.toml +++ b/Project.toml @@ -5,6 +5,7 @@ version = "0.2.0" [deps] Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" +UnitfulAngles = "6fb2a4bd-7999-5318-a3b2-8ad61056cd98" UnitfulEquivalences = "da9c4bc3-91c8-4f02-8a40-6b990d2a7e0c" [compat] diff --git a/src/DimensionfulAngles.jl b/src/DimensionfulAngles.jl index d1efb79..24503c6 100644 --- a/src/DimensionfulAngles.jl +++ b/src/DimensionfulAngles.jl @@ -27,14 +27,18 @@ julia> cos(45ua"°") module DimensionfulAngles # using Base: Base # extend: see `base.jl` for full list of functions extended -using Unitful: Unitful # extend: has_unit_spacing, -using Unitful: minute, promotion, rad, s, 𝐓, 𝐋 -using Unitful: Dimension, DimensionlessQuantity, Frequency, FrequencyFreeUnits, Length -using Unitful: MixedUnits, NoDims, NoUnits, Number, Quantity, Time, Unitlike, Unit, Units -using Unitful: Wavenumber +using Unitful: Unitful # extend: has_unit_spacing, uconvert +using Unitful: minute, promotion, rad, rpm, rps, s, sr, 𝐓, 𝐋, ° +using Unitful: Dimension, Dimensions, DimensionlessQuantity, FreeUnits, Frequency +using Unitful: FrequencyFreeUnits, Length, MixedUnits, NoDims, NoUnits, Number, Quantity +using Unitful: Time, Unitlike, Unit, Units, Wavenumber using Unitful: @dimension, @refunit, @derived_dimension, @unit using Unitful: dimension, register, uconvert, unit, ustrip using UnitfulEquivalences: Equivalence, @eqrelation +using UnitfulAngles: turn, doubleTurn, halfTurn, quadrant, sextant, octant, clockPosition +using UnitfulAngles: hourAngle, compassPoint, hexacontade, brad, diameterPart, grad +using UnitfulAngles: arcminute, arcsecond +# using UnitfulAngles: mas, μas, pas # UnitfulAngles PR #34 export @ua_str export θ₀ @@ -45,7 +49,7 @@ export sexagesimal, show_sexagesimal # export AngularVelocity, AngularVelocityUnits, AngularVelocityFreeUnits # export AngularAcceleration, AngularAccelerationUnits, AngularAccelerationFreeUnits # export AngularPeriod, AngularPeriodUnits, AngularPeriodFreeUnits -# export AngularWavenumber, AngularWavenumberUnits, AngularWavenumberUnits +# export AngularWavenumber, AngularWavenumberUnits, AngularWavenumberFreeUnits # export AngularWavelength, AngularWavelengthUnits, AngularWavelengthFreeUnits """ @@ -139,11 +143,74 @@ julia> 2.1ua"rad" / θ₀ """ const θ₀ = (1 // 1)radᵃ +# Convert to/from Unitful (SI) +function _convert_angles(x::Quantity, input_angle_unit::Units, input_dim::Dimensions, + output_angle_unit::Units, angle_units::NTuple{N, Units} where N, + ) + # convert all units in `angle_units` to common `input_angle_unit` unit. + # cannot use `upreferred` because of `FixedUnits` and `ContextUnits` + AngularUnits = [ + typeof(typeof(angle_unit).parameters[1][1]) for angle_unit in angle_units + ] + + power = 0//1 + input_units = 1 + for iunit in typeof(x).parameters[3].parameters[1] + ipower = iunit.power + if typeof(iunit) ∈ AngularUnits + power += ipower + input_units *= uconvert( + input_angle_unit^ipower, + 1Unitful.FreeUnits{(iunit,), input_dim^ipower, nothing}() + ) + else + input_units *= ( + 1Unitful.FreeUnits{(iunit,), typeof(iunit).parameters[2]^ipower, nothing}() + ) + end + end + input_units = unit(input_units) + x = uconvert(input_units, x) + # convert to output units/dimensions + return x*input_angle_unit^-power*output_angle_unit^power +end + +Unitful.uconvert(s::Symbol, x::Quantity) = Unitful.uconvert(Val{s}(), x) + +function Unitful.uconvert(s::Val{:Unitful}, x::Quantity) + angle_units = ( + radᵃ, °ᵃ, turnᵃ, doubleTurnᵃ, halfTurnᵃ, quadrantᵃ, sextantᵃ, octantᵃ, + clockPositionᵃ, hourAngleᵃ, compassPointᵃ, hexacontadeᵃ, bradᵃ, diameterPartᵃ, + gradᵃ, arcminuteᵃ, arcsecondᵃ, asᵃ, ʰᵃ, ᵐᵃ, ˢᵃ, + ) + x = _convert_angles(x, radᵃ, 𝐀, rad, angle_units) + # derived units that contain angles. + x = _convert_angles(x, srᵃ, 𝐀^2, sr, (srᵃ,)) + x = _convert_angles(x, rpsᵃ, 𝐀*𝐓^-1, rps, (rpsᵃ,)) + x = _convert_angles(x, rpmᵃ, 𝐀*𝐓^-1, rpm, (rpmᵃ,)) + return x +end + +function Unitful.uconvert(s::Val{:DimensionfulAngles}, x::Quantity) + angle_units = ( + rad, °, turn, doubleTurn, halfTurn, quadrant, sextant, octant, clockPosition, + hourAngle, compassPoint, hexacontade, brad, diameterPart, grad, arcminute, + arcsecond, + # TODO: mas, μas, pas # UnitfulAngles PR #34 + ) + x = _convert_angles(x, rad, NoDims, radᵃ, angle_units) + # derived units that contain angles. + x = _convert_angles(x, sr, NoDims, srᵃ, (sr,)) + x = _convert_angles(x, rps, NoDims, rpsᵃ, (rps,)) + x = _convert_angles(x, rpm, NoDims, rpmᵃ, (rpm,)) + return x +end + # Other functionalities. include("units.jl") # Other units of angle. -include("base.jl") # Extend Base functions for units of angle. -include("uamacro.jl") # String macro for using dimensionful units. include("derived.jl") # Units and functionalities for derived dimensions. +include("uamacro.jl") # String macro for using dimensionful units. +include("base.jl") # Extend Base functions for units of angle. include("defaults.jl") # Submodule to flood workspace with unit types. # Register new units and dimensions with Unitful.jl. diff --git a/src/derived.jl b/src/derived.jl index da8d7fe..06942ce 100644 --- a/src/derived.jl +++ b/src/derived.jl @@ -48,7 +48,7 @@ Dimension: 𝐀 𝐓⁻¹. See also [`DimensionfulAngles.radᵃ`](@ref). """ -@unit rpmᵃ "rps" RevolutionsPerMinuteᵃ (1turnᵃ/minute) false +@unit rpmᵃ "rpm" RevolutionsPerMinuteᵃ (1turnᵃ/minute) false # Angular wavenumber, angular wavelength, angular period @derived_dimension AngularWavenumber (𝐀*𝐋^-1) true diff --git a/src/units.jl b/src/units.jl index ea23bd8..90a42ac 100644 --- a/src/units.jl +++ b/src/units.jl @@ -36,9 +36,11 @@ Unitful.has_unit_spacing(u::Units{(Unit{:Arcsecondᵃ, 𝐀}(0, 1 // 1),), 𝐀} @unit diameterPartᵃ "diameterPart" DiameterPartᵃ (1radᵃ//60) false # Turn -@doc __unit_docstr("turn", "turn", "2π rad", "rad", - "Equivalent to a full cycle, revolution, or rotation.") -@unit turnᵃ "τ" Turnᵃ (2π*radᵃ) false +@doc __unit_docstr( + "turn", "turn", "2π rad", "rad", + "Equivalent to a full cycle, revolution, or rotation." +) +@unit turnᵃ "τ" Turnᵃ (360°ᵃ) false # Based on the turn @doc __unit_docstr("doubleTurn", "double turn", "2 turn", "turn")