Created
March 26, 2018 20:38
-
-
Save seivan/83072389d8aca98f77cf7a991f940c31 to your computer and use it in GitHub Desktop.
Drawing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Drawille.Braille do | |
@moduledoc """ | |
Module for a braille code. | |
""" | |
@braille_offset 0x2800 | |
@doc """ | |
You can get "braille byte" by pixel_map. | |
pixel map to n-th bits: | |
| |x=0|x=1| | |
|-- |-- |-- | | |
|y=0| 1 | 4 | | |
|y=1| 2 | 5 | | |
|y=2| 3 | 6 | | |
|y=3| 7 | 8 | | |
""" | |
def pixel_map(0, 0), do: 0x01 | |
def pixel_map(1, 0), do: 0x08 | |
def pixel_map(0, 1), do: 0x02 | |
def pixel_map(1, 1), do: 0x10 | |
def pixel_map(0, 2), do: 0x04 | |
def pixel_map(1, 2), do: 0x20 | |
def pixel_map(0, 3), do: 0x40 | |
def pixel_map(1, 3), do: 0x80 | |
@doc """ | |
Get a printable UTF8 code. | |
""" | |
def to_utf8_code(0), do: @braille_offset | |
def to_utf8_code braille_byte do | |
braille_byte + @braille_offset | |
end | |
end | |
defmodule Drawille.Canvas do | |
@moduledoc """ | |
Module for still drawing. | |
""" | |
defstruct chars: %{}, top_left: :undefined, down_right: :undefined | |
use Bitwise | |
alias Drawille.Canvas, as: Canvas | |
alias Drawille.Braille, as: Braille | |
@doc """ | |
Make new empty canvas. | |
""" | |
def new, do: %Canvas{} | |
@doc """ | |
Set a dot at (x, y) to a canvas. | |
""" | |
def set(%{chars: chars, top_left: top_left, down_right: down_right}, x, y) | |
when x > 0 and y > 0 | |
do | |
{{chars_x, chars_y} = chars_xy, {dots_x, dots_y}} = normalize x, y | |
braille_byte_to_be_set = Braille.pixel_map(dots_x, dots_y) | |
chars = case Map.fetch chars, chars_xy do | |
{:ok, char0} -> Map.put(chars, chars_xy, char0 ||| braille_byte_to_be_set) | |
:error -> Map.put_new(chars, chars_xy, braille_byte_to_be_set) | |
end | |
top_left = case top_left do | |
:undefined -> chars_xy | |
{top_left_x, top_left_y} -> {min(top_left_x, chars_x), min(top_left_y, chars_y)} | |
end | |
down_right = case down_right do | |
:undefined -> chars_xy | |
{down_right_x, down_right_y} -> {max(down_right_x, chars_x), max(down_right_y, chars_y)} | |
end | |
%Canvas{ | |
chars: chars, | |
top_left: top_left, | |
down_right: down_right} | |
end | |
def set(_, x, y) do | |
raise("x(#{x}) and y(#{y}) must be positive.") | |
end | |
@doc """ | |
Unset a dot at (x, y) from a canvas. | |
""" | |
def unset(canvas = %{chars: chars}, x, y) | |
when x > 0 and y > 0 | |
do | |
{chars_xy, {dots_x, dots_y}} = normalize x, y | |
braille_byte_to_be_unset = Braille.pixel_map(dots_x, dots_y) | |
chars = case Map.fetch chars, chars_xy do | |
{:ok, char0} -> | |
case char0 &&& braille_byte_to_be_unset do | |
0 -> chars | |
_ -> | |
case bxor(char0, braille_byte_to_be_unset) do | |
0 -> Map.delete(chars, chars_xy) | |
new_char -> Map.put(chars, chars_xy, new_char) | |
end | |
end | |
:error -> chars | |
end | |
%{canvas | chars: chars} | |
end | |
@doc """ | |
Draw a canvas. | |
""" | |
def frame %{chars: chars, top_left: {tl_x, tl_y}, down_right: {dr_x, dr_y}} do | |
frame_string = | |
for y <- tl_y .. dr_y, | |
x <- tl_x .. dr_x, | |
into: "" | |
do | |
char = | |
case Map.fetch chars, {x, y} do | |
{:ok, char} -> char | |
:error -> 0 | |
end | |
code = Braille.to_utf8_code char | |
string = <<code :: utf8>> | |
if x == dr_x do | |
string <> "\n" | |
else | |
string | |
end | |
end | |
IO.puts frame_string | |
end | |
defp normalize x, y do | |
rounded_x = Kernel.round x | |
rounded_y = Kernel.round y | |
chars_x = div rounded_x, 2 | |
chars_y = div rounded_y, 4 | |
dots_x = rem rounded_x, 2 | |
dots_y = rem rounded_y, 4 | |
{{chars_x, chars_y}, {dots_x, dots_y}} | |
end | |
end | |
defmodule Drawille.Examples.Circular do | |
alias Drawille.Canvas | |
def test do | |
1..5 |> Enum.map(fn(x) -> | |
Rect.new(x * 10, x * 10, 20, 20 ) | |
end) | |
|> Enum.each(fn(x) -> | |
sx = x |> Rect.min(:x) | |
ex = x |> Rect.max(:x) | |
sy = x |> Rect.min(:y) | |
ey = x |> Rect.max(:y) | |
canvas = sx..ex |> Enum.reduce(Canvas.new, fn(dot, canvas) -> | |
Canvas.set(canvas, dot, sy) | |
end) | |
canvas = sy..ey |> Enum.reduce(canvas, fn(dot, canvas) -> | |
Canvas.set(canvas, ex, dot) | |
end) | |
canvas = ex..sx |> Enum.reduce(canvas, fn(dot, canvas) -> | |
Canvas.set(canvas, dot, ey) | |
end) | |
canvas = ey..sy |> Enum.reduce(canvas, fn(dot, canvas) -> | |
Canvas.set(canvas, sx, dot) | |
end) | |
Canvas.frame(canvas) | |
end) | |
end | |
def test2 do | |
n = 200 | |
Enum.reduce(1..n, Canvas.new, | |
fn(t, acc_canvas) -> | |
theta = 2 * :math.pi * (t/200) | |
x = 30 * :math.cos(theta) + 40 | |
y = 30 * :math.sin(theta) + 40 | |
Canvas.set(acc_canvas, x, y) | |
end) | |
|> Canvas.frame | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment