Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Trigonometric Functions

trig.livemd

Trigonometric Functions

Mix.install([
  {:kino, "~> 0.14.2"}
])

Introduction

Trigonometric functions are provided by the Erlang :math module. These map between an angle of a right-angled triangle and the ratios of two side lengths. Specifically, in this workbook we explore the sine and cosine functions. They operate on angles measured in radians. An angle of $360^\circ$ corresponds to $2\cdot \pi$ radians.

References:

Visualization

defmodule Visualization do
  @dim 256
  @r (@dim*0.7)
  
  defp deg2rad(degrees), do: 2*:math.pi*degrees/360

  def produce_coordinate_system() do
    style = "stroke-width=\"4\" stroke=\"black\" stroke-opacity=\"0.1\""
    """
    
    
    """
  end
  
  def produce_unit_circle() do
    """
    
    """
  end
  
  def produce_hand(x, y) do
    """
    
    
    """
  end
  
  def produce_decoration(a, x, y) do
    {xlabel_offset, xlabel_baseline} =
      if y<0 do
        {20, "auto"}
      else
        {-20, "hanging"}
      end
    {ylabel_offset, ylabel_anchor} =
      if x<0 do
        {10, "start"}
      else
        {-10, "end"}
      end
    deg = a |> :erlang.float_to_binary([decimals: 0])
    line_props = "stroke-width=\"2\" stroke=\"orange\" stroke-dasharray=\"5,5\""
    """
    
    
      cos(#{deg}°) = #{x |> :erlang.float_to_binary([decimals: 2])}
    
    
    
    
      sin(#{deg}°) = #{y |> :erlang.float_to_binary([decimals: 2])}
    
    """
  end
  
  def produce_angle(deg, rad) do
    x = 1.35*@r*0.5*:math.cos(rad/2)
    y = 1.35*@r*0.5*:math.sin(rad/2) * -1
    direction = if deg<180 do 0 else 1 end
    endx = @r*0.5*:math.cos(rad)
    endy = @r*0.5*:math.sin(rad) * -1
    """
    
    
    
      α = #{deg |> :erlang.float_to_binary([decimals: 0])}°
    
    """
  end
  
  def update_angle(angle, frame) do
    a = deg2rad(angle)
    x = :math.cos(a)
    y = :math.sin(a) * -1

    coordinate_lines = produce_coordinate_system()
    circle_lines = produce_unit_circle()
    hand_lines = produce_hand(x, y)
    decoration_lines = produce_decoration(angle, x, y)
    angle_lines = produce_angle(angle, a)

    svg_kino =
      """
      
        #{circle_lines}
        #{hand_lines}
        #{decoration_lines}
        #{coordinate_lines}
        #{angle_lines}
      
      """
      |> Kino.Image.new(:svg)
    Kino.Frame.render(frame, svg_kino)
  end
end

Interface

kino = Kino.Input.range("Pick an angle:", min: 0, max: 360, default: 34, debounce: 1)
frame = Kino.Frame.new() |> Kino.render()
nil
Kino.listen(kino, fn event ->
  Visualization.update_angle(event.value, frame)
end)