Implement abs
for each angle.
This commit is contained in:
parent
7b021e8a83
commit
d606863684
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -9,6 +9,7 @@
|
|||
|
||||
# Where 3rd-party dependencies like ExDoc output generated docs.
|
||||
/doc/
|
||||
/docs/
|
||||
|
||||
# Ignore .fetch files in case you like to edit your project deps locally.
|
||||
/.fetch
|
||||
|
|
File diff suppressed because one or more lines are too long
59
lib/angle.ex
59
lib/angle.ex
|
@ -1,5 +1,7 @@
|
|||
defmodule Angle do
|
||||
defstruct ~w(d r g dms)a
|
||||
alias Angle.{Radian, Gradian, Degree, DMS, Trig}
|
||||
|
||||
@moduledoc """
|
||||
Tired of forever converting back and forwards between degrees and radians?
|
||||
Well worry no more; Angle is here to make your life simple!
|
||||
|
@ -61,10 +63,10 @@ defmodule Angle do
|
|||
end
|
||||
end
|
||||
|
||||
defdelegate degrees(n), to: Angle.Degree, as: :init
|
||||
defdelegate radians(n), to: Angle.Radian, as: :init
|
||||
defdelegate gradians(n), to: Angle.Gradian, as: :init
|
||||
defdelegate dms(d, m, s), to: Angle.DMS, as: :init
|
||||
defdelegate degrees(n), to: Degree, as: :init
|
||||
defdelegate radians(n), to: Radian, as: :init
|
||||
defdelegate gradians(n), to: Gradian, as: :init
|
||||
defdelegate dms(d, m, s), to: DMS, as: :init
|
||||
|
||||
@doc """
|
||||
Initialize and Angle with zero values
|
||||
|
@ -77,8 +79,49 @@ defmodule Angle do
|
|||
@spec zero() :: t
|
||||
def zero, do: %Angle{d: 0, r: 0, g: 0}
|
||||
|
||||
defdelegate to_radians(angle), to: Angle.Radian
|
||||
defdelegate to_degrees(angle), to: Angle.Degree
|
||||
defdelegate to_gradians(angle), to: Angle.Gradian
|
||||
defdelegate to_dms(angle), to: Angle.DMS
|
||||
defdelegate to_radians(angle), to: Radian
|
||||
defdelegate to_degrees(angle), to: Degree
|
||||
defdelegate to_gradians(angle), to: Gradian
|
||||
defdelegate to_dms(angle), to: DMS
|
||||
|
||||
defdelegate acos(x), to: Trig
|
||||
defdelegate acosh(x), to: Trig
|
||||
defdelegate asin(x), to: Trig
|
||||
defdelegate asinh(x), to: Trig
|
||||
defdelegate atan(x), to: Trig
|
||||
defdelegate atan2(x, y), to: Trig
|
||||
defdelegate cos(angle), to: Trig
|
||||
defdelegate cosh(angle), to: Trig
|
||||
defdelegate sin(angle), to: Trig
|
||||
defdelegate sinh(angle), to: Trig
|
||||
defdelegate tan(angle), to: Trig
|
||||
defdelegate tanh(angle), to: Trig
|
||||
|
||||
@doc """
|
||||
Convert the angle to it's absolute value by discarding complete revolutions
|
||||
and converting negatives.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> ~a(-270)d
|
||||
...> |> Angle.abs()
|
||||
#Angle<90°>
|
||||
|
||||
iex> ~a(-4.71238898038469)r
|
||||
...> |> Angle.abs()
|
||||
#Angle<1.5707963267948966㎭>
|
||||
|
||||
iex> ~a(-270,15,45)dms
|
||||
...> |> Angle.abs()
|
||||
#Angle<90° 45′ 15″>
|
||||
|
||||
iex> ~a(-300)g
|
||||
...> |> Angle.abs()
|
||||
#Angle<100ᵍ>
|
||||
"""
|
||||
@spec abs(Angle.t) :: Angle.t
|
||||
def abs(%Angle{r: r} = angle) when is_number(r), do: Radian.abs(angle)
|
||||
def abs(%Angle{d: d} = angle) when is_number(d), do: Degree.abs(angle)
|
||||
def abs(%Angle{g: g} = angle) when is_number(g), do: Gradian.abs(angle)
|
||||
def abs(%Angle{dms: {d, m, s}} = angle) when is_number(d) and is_number(m) and is_number(s), do: DMS.abs(angle)
|
||||
end
|
||||
|
|
|
@ -35,10 +35,13 @@ defmodule Angle.Degree do
|
|||
|
||||
iex> "13.2°" |> parse() |> inspect()
|
||||
"{:ok, #Angle<13.2°>}"
|
||||
|
||||
iex> "-13.2°" |> parse() |> inspect()
|
||||
"{:ok, #Angle<-13.2°>}"
|
||||
"""
|
||||
@spec parse(String.t) :: {:ok, Angle.t} | {:error, term}
|
||||
def parse(value) do
|
||||
case Regex.run(~r/^[0-9]+(?:\.[0-9]+)?/, value) do
|
||||
case Regex.run(~r/^-?[0-9]+(?:\.[0-9]+)?/, value) do
|
||||
[value] ->
|
||||
case string_to_number(value) do
|
||||
{:ok, n} -> {:ok, init(n)}
|
||||
|
@ -100,4 +103,25 @@ defmodule Angle.Degree do
|
|||
@spec to_degrees(Angle.t) :: {Angle.t, number}
|
||||
def to_degrees(%Angle{d: number} = angle) when is_number(number), do: {angle, number}
|
||||
def to_degrees(angle), do: angle |> ensure() |> to_degrees()
|
||||
|
||||
@doc """
|
||||
Convert the angle to it's absolute value by discarding complete revolutions
|
||||
and converting negatives.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> ~a(-270)d
|
||||
...> |> Angle.Degree.abs()
|
||||
#Angle<90°>
|
||||
|
||||
iex> ~a(1170)d
|
||||
...> |> Angle.Degree.abs()
|
||||
#Angle<90°>
|
||||
"""
|
||||
@spec abs(Angle.t) :: Angle.t
|
||||
def abs(%Angle{d: d}), do: init(calculate_abs(d))
|
||||
|
||||
defp calculate_abs(d) when d >= 0 and d <= 360, do: d
|
||||
defp calculate_abs(d) when d > 360, do: calculate_abs(d - 360)
|
||||
defp calculate_abs(d) when d < 0, do: calculate_abs(d + 360)
|
||||
end
|
||||
|
|
|
@ -5,7 +5,7 @@ defmodule Angle.DMS do
|
|||
Functions relating to dealing with angles in Degrees, Minutes and Seconds.
|
||||
"""
|
||||
|
||||
@parser ~r/([0-9]+)
|
||||
@parser ~r/(-?[0-9]+)
|
||||
(?:[\x{00b0},\ ]?\ *)
|
||||
([0-9]+)
|
||||
(?:[\x{2032}',\ ]?\ *)
|
||||
|
@ -63,6 +63,9 @@ defmodule Angle.DMS do
|
|||
|
||||
iex> "166°45′58.46″" |> parse() |> inspect()
|
||||
"{:ok, #Angle<166° 45′ 58.46″>}"
|
||||
|
||||
iex> "-166° 45′ 58.46″" |> parse() |> inspect()
|
||||
"{:ok, #Angle<-166° 45′ 58.46″>}"
|
||||
"""
|
||||
@spec parse(String.t) :: {:ok, Angle.t} | {:error, term}
|
||||
def parse(value) do
|
||||
|
@ -136,4 +139,26 @@ defmodule Angle.DMS do
|
|||
@spec to_dms(Angle.t) :: {Angle.t, {integer, integer, number}}
|
||||
def to_dms(%Angle{dms: {d, m, s}} = angle), do: {angle, {d, m, s}}
|
||||
def to_dms(%Angle{} = angle), do: angle |> ensure() |> to_dms()
|
||||
|
||||
@doc """
|
||||
Convert the angle to it's absolute value by discarding complete revolutions
|
||||
and converting negatives.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> ~a(-270,15,45)dms
|
||||
...> |> Angle.DMS.abs()
|
||||
#Angle<90° 45′ 15″>
|
||||
|
||||
iex> ~a(1170,0,0)dms
|
||||
...> |> Angle.DMS.abs()
|
||||
#Angle<90°>
|
||||
"""
|
||||
@spec abs(Angle.t) :: Angle.t
|
||||
def abs(%Angle{dms: {d, m, s}}), do: %Angle{dms: calculate_abs(d, m, s)}
|
||||
|
||||
defp calculate_abs(d, m, s) when d >= 0 and d <= 360, do: {d, m, s}
|
||||
defp calculate_abs(d, m, s) when d > 360, do: calculate_abs(d - 360, m, s)
|
||||
defp calculate_abs(d, m, s) when d < -360, do: calculate_abs(d + 360, m, s)
|
||||
defp calculate_abs(d, m, s) when d < 0, do: calculate_abs(d + 360, 60 - m, 60 - s)
|
||||
end
|
||||
|
|
|
@ -39,7 +39,7 @@ defmodule Angle.Gradian do
|
|||
"""
|
||||
@spec parse(String.t) :: {:ok, Angle.t} | {:error, term}
|
||||
def parse(value) do
|
||||
case Regex.run(~r/^[0-9]+(?:\.[0-9]+)?/, value) do
|
||||
case Regex.run(~r/^-?[0-9]+(?:\.[0-9]+)?/, value) do
|
||||
[value] ->
|
||||
case string_to_number(value) do
|
||||
{:ok, n} -> {:ok, init(n)}
|
||||
|
@ -109,4 +109,24 @@ defmodule Angle.Gradian do
|
|||
|> to_gradians()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Convert the angle to it's absolute value by discarding complete revolutions
|
||||
and converting negatives.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> ~a(-300)g
|
||||
...> |> Angle.Gradian.abs()
|
||||
#Angle<100ᵍ>
|
||||
|
||||
iex> ~a(1300)g
|
||||
...> |> Angle.Gradian.abs()
|
||||
#Angle<100ᵍ>
|
||||
"""
|
||||
@spec abs(Angle.t) :: Angle.t
|
||||
def abs(%Angle{g: g}), do: init(calculate_abs(g))
|
||||
|
||||
defp calculate_abs(g) when g >= 0 and g <= 400, do: g
|
||||
defp calculate_abs(g) when g > 400, do: calculate_abs(g - 400)
|
||||
defp calculate_abs(g) when g < 0, do: calculate_abs(g + 400)
|
||||
end
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
defmodule Angle.Radian do
|
||||
import Angle.Utils, only: [string_to_number: 1]
|
||||
|
||||
@moduledoc """
|
||||
Functions relating to dealing with angles in Radians.
|
||||
"""
|
||||
|
||||
@two_pi 2 * :math.pi()
|
||||
|
||||
@doc """
|
||||
Initialize an Angle from a number `n` of radians
|
||||
|
||||
|
@ -20,7 +23,7 @@ defmodule Angle.Radian do
|
|||
def init(n) when is_number(n), do: %Angle{r: n}
|
||||
|
||||
@doc """
|
||||
Attempt to arse decimal radians.
|
||||
Attempt to parse decimal radians.
|
||||
|
||||
## Examples
|
||||
|
||||
|
@ -35,10 +38,13 @@ defmodule Angle.Radian do
|
|||
|
||||
iex> "13.2㎭" |> parse() |> inspect()
|
||||
"{:ok, #Angle<13.2㎭>}"
|
||||
|
||||
iex> "-13.2㎭" |> parse() |> inspect()
|
||||
"{:ok, #Angle<-13.2㎭>}"
|
||||
"""
|
||||
@spec parse(String.t) :: {:ok, Angle.t} | {:error, term}
|
||||
def parse(value) do
|
||||
case Regex.run(~r/^[0-9]+(?:\.[0-9]+)?/, value) do
|
||||
case Regex.run(~r/^-?[0-9]+(?:\.[0-9]+)?/, value) do
|
||||
[value] ->
|
||||
case string_to_number(value) do
|
||||
{:ok, n} -> {:ok, init(n)}
|
||||
|
@ -94,12 +100,12 @@ defmodule Angle.Radian do
|
|||
|
||||
## Examples
|
||||
|
||||
iex> use Angle
|
||||
...> ~a(90)d
|
||||
...> |> Angle.Radian.to_radians()
|
||||
iex> ~a(90)d
|
||||
...> |> to_radians()
|
||||
...> |> inspect()
|
||||
"{#Angle<90°>, 1.5707963267948966}"
|
||||
"""
|
||||
@spec to_radians(Angle.t) :: {Angle.t, number}
|
||||
def to_radians(%Angle{r: number} = angle) when is_number(number), do: {angle, number}
|
||||
def to_radians(angle) do
|
||||
angle
|
||||
|
@ -107,4 +113,24 @@ defmodule Angle.Radian do
|
|||
|> to_radians()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Convert the angle to it's absolute value by discarding complete revolutions
|
||||
and converting negatives.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> ~a(-4.71238898038469)r
|
||||
...> |> Angle.Radian.abs()
|
||||
#Angle<1.5707963267948966㎭>
|
||||
|
||||
iex> ~a(20.420352248333657)r
|
||||
...> |> Angle.Radian.abs()
|
||||
#Angle<1.5707963267948983㎭>
|
||||
"""
|
||||
@spec abs(Angle.t) :: Angle.t
|
||||
def abs(%Angle{r: r}), do: init(calculate_abs(r))
|
||||
|
||||
defp calculate_abs(r) when r >= 0 and r <= @two_pi, do: r
|
||||
defp calculate_abs(r) when r > @two_pi, do: calculate_abs(r - @two_pi)
|
||||
defp calculate_abs(r) when r < 0, do: calculate_abs(r + @two_pi)
|
||||
end
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
defmodule AngleTest do
|
||||
use ExUnit.Case
|
||||
import Angle.Sigil
|
||||
doctest Angle
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue