Fix bugs in circle and line rasterizing.
This commit is contained in:
parent
7c4a4161f1
commit
f09bf246d8
4 changed files with 66 additions and 27 deletions
16
lib/vivid.ex
16
lib/vivid.ex
|
@ -1,2 +1,18 @@
|
||||||
defmodule Vivid do
|
defmodule Vivid do
|
||||||
|
|
||||||
|
def example do
|
||||||
|
polygon = [{1,1}, {1,4}, {4,4}, {4,1}]
|
||||||
|
|> Enum.map(fn {x,y} -> Vivid.Point.init(x,y) end)
|
||||||
|
|> Vivid.Polygon.init
|
||||||
|
|
||||||
|
line = [{9,1}, {1,9}]
|
||||||
|
|> Enum.map(fn {x,y} -> Vivid.Point.init(x,y) end)
|
||||||
|
|> Vivid.Line.init
|
||||||
|
|
||||||
|
Vivid.Frame.init(10,10)
|
||||||
|
|> Vivid.Frame.push(polygon, 1)
|
||||||
|
|> Vivid.Frame.push(line, 1)
|
||||||
|
|> Vivid.Frame.puts
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -74,15 +74,15 @@ defmodule Vivid.Frame do
|
||||||
...> |> Vivid.Frame.push(circle, 1)
|
...> |> Vivid.Frame.push(circle, 1)
|
||||||
...> |> Vivid.Frame.to_string
|
...> |> Vivid.Frame.to_string
|
||||||
"...........\n" <>
|
"...........\n" <>
|
||||||
".....X.....\n" <>
|
"....XXX....\n" <>
|
||||||
"..X.....X..\n" <>
|
"..XX...XX..\n" <>
|
||||||
"..X.....X..\n" <>
|
"..X.....X..\n" <>
|
||||||
".X.......X.\n" <>
|
".X.......X.\n" <>
|
||||||
".X.......X.\n" <>
|
".X.......X.\n" <>
|
||||||
".X.......X.\n" <>
|
".X.......X.\n" <>
|
||||||
"..X.....X..\n" <>
|
"..X.....X..\n" <>
|
||||||
"..X.....X..\n" <>
|
"..XX...XX..\n" <>
|
||||||
".....X.....\n"
|
"....XXX....\n"
|
||||||
|
|
||||||
iex> line = Vivid.Line.init(Vivid.Point.init(0,0), Vivid.Point.init(50,50))
|
iex> line = Vivid.Line.init(Vivid.Point.init(0,0), Vivid.Point.init(50,50))
|
||||||
...> Vivid.Frame.init(5,5)
|
...> Vivid.Frame.init(5,5)
|
||||||
|
@ -97,9 +97,13 @@ defmodule Vivid.Frame do
|
||||||
def push(%Frame{buffer: buffer, colour_depth: c, width: w}=frame, shape, colour) when colour <= c do
|
def push(%Frame{buffer: buffer, colour_depth: c, width: w}=frame, shape, colour) when colour <= c do
|
||||||
points = Vivid.Rasterize.rasterize(shape)
|
points = Vivid.Rasterize.rasterize(shape)
|
||||||
buffer = Enum.reduce(points, buffer, fn(point, buffer) ->
|
buffer = Enum.reduce(points, buffer, fn(point, buffer) ->
|
||||||
x = point |> Point.x
|
if point_inside_bounds?(point, frame) do
|
||||||
y = point |> Point.y
|
x = point |> Point.x
|
||||||
List.replace_at(buffer, (x * w) + y, colour)
|
y = point |> Point.y
|
||||||
|
List.replace_at(buffer, (x * w) + y, colour)
|
||||||
|
else
|
||||||
|
buffer
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
%{frame | buffer: buffer}
|
%{frame | buffer: buffer}
|
||||||
end
|
end
|
||||||
|
@ -143,4 +147,10 @@ defmodule Vivid.Frame do
|
||||||
defp allocate_buffer(size) do
|
defp allocate_buffer(size) do
|
||||||
Enum.map((1..size), fn(_) -> 0 end)
|
Enum.map((1..size), fn(_) -> 0 end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp point_inside_bounds?(%Point{x: x}, _frame) when x < 0, do: false
|
||||||
|
defp point_inside_bounds?(%Point{y: y}, _frame) when y < 0, do: false
|
||||||
|
defp point_inside_bounds?(%Point{x: x}, %Frame{width: w}) when x >= w, do: false
|
||||||
|
defp point_inside_bounds?(%Point{y: y}, %Frame{height: h}) when y >= h, do: false
|
||||||
|
defp point_inside_bounds?(_point, _frame), do: true
|
||||||
end
|
end
|
|
@ -1,5 +1,5 @@
|
||||||
defimpl Vivid.Rasterize, for: Vivid.Circle do
|
defimpl Vivid.Rasterize, for: Vivid.Circle do
|
||||||
alias Vivid.{Circle, Point}
|
alias Vivid.{Circle, Point, Polygon, Rasterize}
|
||||||
import :math, only: [pow: 2, sqrt: 1]
|
import :math, only: [pow: 2, sqrt: 1]
|
||||||
|
|
||||||
@moduledoc """
|
@moduledoc """
|
||||||
|
@ -19,14 +19,18 @@ defimpl Vivid.Rasterize, for: Vivid.Circle do
|
||||||
iex> Vivid.Circle.init(Vivid.Point.init(5,5), 4)
|
iex> Vivid.Circle.init(Vivid.Point.init(5,5), 4)
|
||||||
...> |> Vivid.Rasterize.rasterize
|
...> |> Vivid.Rasterize.rasterize
|
||||||
MapSet.new([
|
MapSet.new([
|
||||||
%Vivid.Point{x: 1, y: 5}, %Vivid.Point{x: 2, y: 2},
|
%Vivid.Point{x: 1, y: 4}, %Vivid.Point{x: 1, y: 5},
|
||||||
|
%Vivid.Point{x: 1, y: 6}, %Vivid.Point{x: 2, y: 2},
|
||||||
|
%Vivid.Point{x: 2, y: 3}, %Vivid.Point{x: 2, y: 7},
|
||||||
%Vivid.Point{x: 2, y: 8}, %Vivid.Point{x: 3, y: 2},
|
%Vivid.Point{x: 2, y: 8}, %Vivid.Point{x: 3, y: 2},
|
||||||
%Vivid.Point{x: 3, y: 8}, %Vivid.Point{x: 4, y: 1},
|
%Vivid.Point{x: 3, y: 8}, %Vivid.Point{x: 4, y: 1},
|
||||||
%Vivid.Point{x: 4, y: 9}, %Vivid.Point{x: 5, y: 1},
|
%Vivid.Point{x: 4, y: 9}, %Vivid.Point{x: 5, y: 1},
|
||||||
%Vivid.Point{x: 5, y: 9}, %Vivid.Point{x: 6, y: 1},
|
%Vivid.Point{x: 5, y: 9}, %Vivid.Point{x: 6, y: 1},
|
||||||
%Vivid.Point{x: 6, y: 9}, %Vivid.Point{x: 7, y: 2},
|
%Vivid.Point{x: 6, y: 9}, %Vivid.Point{x: 7, y: 2},
|
||||||
%Vivid.Point{x: 7, y: 8}, %Vivid.Point{x: 8, y: 2},
|
%Vivid.Point{x: 7, y: 8}, %Vivid.Point{x: 8, y: 2},
|
||||||
%Vivid.Point{x: 8, y: 8}, %Vivid.Point{x: 9, y: 5}
|
%Vivid.Point{x: 8, y: 3}, %Vivid.Point{x: 8, y: 7},
|
||||||
|
%Vivid.Point{x: 8, y: 8}, %Vivid.Point{x: 9, y: 4},
|
||||||
|
%Vivid.Point{x: 9, y: 5}, %Vivid.Point{x: 9, y: 6}
|
||||||
])
|
])
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -35,16 +39,20 @@ defimpl Vivid.Rasterize, for: Vivid.Circle do
|
||||||
y_center = point |> Point.y
|
y_center = point |> Point.y
|
||||||
r_squared = pow(radius, 2)
|
r_squared = pow(radius, 2)
|
||||||
|
|
||||||
Enum.reduce(0-radius..radius, MapSet.new, fn (x, points) ->
|
{points0, points1} = Enum.reduce(0-radius..radius, {[], []}, fn (x, {points0, points1}) ->
|
||||||
y = sqrt(r_squared - pow(x, 2)) |> round
|
y = sqrt(r_squared - pow(x, 2)) |> round
|
||||||
|
x = x_center + x
|
||||||
x = x_center + x
|
y0 = y_center - y
|
||||||
y0 = y_center + y
|
y1 = y_center + y
|
||||||
y1 = y_center - y
|
points0 = [ Point.init(x, y0) | points0 ]
|
||||||
|
points1 = [ Point.init(x, y1) | points1 ]
|
||||||
points
|
{points0, points1}
|
||||||
|> MapSet.put(Point.init(x, y0))
|
|
||||||
|> MapSet.put(Point.init(x, y1))
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
points1 = points1 |> Enum.reverse
|
||||||
|
|
||||||
|
points0 ++ points1
|
||||||
|
|> Polygon.init
|
||||||
|
|> Rasterize.rasterize
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -36,20 +36,25 @@ defimpl Vivid.Rasterize, for: Vivid.Line do
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def rasterize(%Line{}=line) do
|
def rasterize(%Line{}=line) do
|
||||||
|
origin = line |> Line.origin
|
||||||
dx = line |> Line.x_distance
|
dx = line |> Line.x_distance
|
||||||
dy = line |> Line.y_distance
|
dy = line |> Line.y_distance
|
||||||
|
|
||||||
steps = choose_largest_of(abs(dx), abs(dy))
|
steps = choose_largest_of(abs(dx), abs(dy))
|
||||||
x_increment = dx / steps
|
|
||||||
y_increment = dy / steps
|
|
||||||
|
|
||||||
origin = line |> Line.origin
|
if steps == 0 do
|
||||||
|
MapSet.new([origin])
|
||||||
|
else
|
||||||
|
x_increment = dx / steps
|
||||||
|
y_increment = dy / steps
|
||||||
|
|
||||||
points = MapSet.new([origin])
|
|
||||||
current_x = origin |> Point.x
|
|
||||||
current_y = origin |> Point.y
|
|
||||||
|
|
||||||
reduce_points(points, steps, current_x, current_y, x_increment, y_increment)
|
points = MapSet.new([origin])
|
||||||
|
current_x = origin |> Point.x
|
||||||
|
current_y = origin |> Point.y
|
||||||
|
|
||||||
|
reduce_points(points, steps, current_x, current_y, x_increment, y_increment)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp reduce_points(points, 0, _, _, _, _), do: points
|
defp reduce_points(points, 0, _, _, _, _), do: points
|
||||||
|
|
Loading…
Reference in a new issue