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
|
||||
|
||||
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
|
||||
|
|
|
@ -74,15 +74,15 @@ defmodule Vivid.Frame do
|
|||
...> |> Vivid.Frame.push(circle, 1)
|
||||
...> |> Vivid.Frame.to_string
|
||||
"...........\n" <>
|
||||
".....X.....\n" <>
|
||||
"..X.....X..\n" <>
|
||||
"....XXX....\n" <>
|
||||
"..XX...XX..\n" <>
|
||||
"..X.....X..\n" <>
|
||||
".X.......X.\n" <>
|
||||
".X.......X.\n" <>
|
||||
".X.......X.\n" <>
|
||||
"..X.....X..\n" <>
|
||||
"..X.....X..\n" <>
|
||||
".....X.....\n"
|
||||
"..XX...XX..\n" <>
|
||||
"....XXX....\n"
|
||||
|
||||
iex> line = Vivid.Line.init(Vivid.Point.init(0,0), Vivid.Point.init(50,50))
|
||||
...> 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
|
||||
points = Vivid.Rasterize.rasterize(shape)
|
||||
buffer = Enum.reduce(points, buffer, fn(point, buffer) ->
|
||||
if point_inside_bounds?(point, frame) do
|
||||
x = point |> Point.x
|
||||
y = point |> Point.y
|
||||
List.replace_at(buffer, (x * w) + y, colour)
|
||||
else
|
||||
buffer
|
||||
end
|
||||
end)
|
||||
%{frame | buffer: buffer}
|
||||
end
|
||||
|
@ -143,4 +147,10 @@ defmodule Vivid.Frame do
|
|||
defp allocate_buffer(size) do
|
||||
Enum.map((1..size), fn(_) -> 0 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
|
|
@ -1,5 +1,5 @@
|
|||
defimpl Vivid.Rasterize, for: Vivid.Circle do
|
||||
alias Vivid.{Circle, Point}
|
||||
alias Vivid.{Circle, Point, Polygon, Rasterize}
|
||||
import :math, only: [pow: 2, sqrt: 1]
|
||||
|
||||
@moduledoc """
|
||||
|
@ -19,14 +19,18 @@ defimpl Vivid.Rasterize, for: Vivid.Circle do
|
|||
iex> Vivid.Circle.init(Vivid.Point.init(5,5), 4)
|
||||
...> |> Vivid.Rasterize.rasterize
|
||||
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: 3, y: 8}, %Vivid.Point{x: 4, 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: 6, y: 9}, %Vivid.Point{x: 7, 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
|
||||
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
|
||||
|
||||
x = x_center + x
|
||||
y0 = y_center + y
|
||||
y1 = y_center - y
|
||||
|
||||
points
|
||||
|> MapSet.put(Point.init(x, y0))
|
||||
|> MapSet.put(Point.init(x, y1))
|
||||
y0 = y_center - y
|
||||
y1 = y_center + y
|
||||
points0 = [ Point.init(x, y0) | points0 ]
|
||||
points1 = [ Point.init(x, y1) | points1 ]
|
||||
{points0, points1}
|
||||
end)
|
||||
|
||||
points1 = points1 |> Enum.reverse
|
||||
|
||||
points0 ++ points1
|
||||
|> Polygon.init
|
||||
|> Rasterize.rasterize
|
||||
end
|
||||
end
|
|
@ -36,14 +36,18 @@ defimpl Vivid.Rasterize, for: Vivid.Line do
|
|||
|
||||
"""
|
||||
def rasterize(%Line{}=line) do
|
||||
origin = line |> Line.origin
|
||||
dx = line |> Line.x_distance
|
||||
dy = line |> Line.y_distance
|
||||
|
||||
steps = choose_largest_of(abs(dx), abs(dy))
|
||||
|
||||
if steps == 0 do
|
||||
MapSet.new([origin])
|
||||
else
|
||||
x_increment = dx / steps
|
||||
y_increment = dy / steps
|
||||
|
||||
origin = line |> Line.origin
|
||||
|
||||
points = MapSet.new([origin])
|
||||
current_x = origin |> Point.x
|
||||
|
@ -51,6 +55,7 @@ defimpl Vivid.Rasterize, for: Vivid.Line do
|
|||
|
||||
reduce_points(points, steps, current_x, current_y, x_increment, y_increment)
|
||||
end
|
||||
end
|
||||
|
||||
defp reduce_points(points, 0, _, _, _, _), do: points
|
||||
|
||||
|
|
Loading…
Reference in a new issue