Fix bugs in circle and line rasterizing.

This commit is contained in:
James Harton 2016-12-22 14:04:29 +13:00
parent 7c4a4161f1
commit f09bf246d8
4 changed files with 66 additions and 27 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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