Add shape groups.

This commit is contained in:
James Harton 2016-12-23 11:07:33 +13:00
parent 2c5cbba334
commit 6d5463d2b5
8 changed files with 167 additions and 0 deletions

View file

@ -0,0 +1,20 @@
defimpl Collectable, for: Vivid.Group do
alias Vivid.Group
@doc """
Collect an enumerable into a Group.
## Examples
iex> [Vivid.Point.init(1,1)] |> Enum.into(Vivid.Group.init)
%Vivid.Group{shapes: MapSet.new([%Vivid.Point{x: 1, y: 1}])}
"""
def into(%Group{shapes: shapes}) do
{MapSet.new, fn
new_shapes, {:cont, shape} -> MapSet.put(new_shapes, shape)
new_shapes, :done -> Group.init(MapSet.union(shapes, new_shapes))
_, :halt -> :ok
end}
end
end

View file

@ -0,0 +1,44 @@
defimpl Enumerable, for: Vivid.Group do
alias Vivid.Group
@moduledoc """
Implements the Enumerable protocol for %Group{}
"""
@doc """
Returns the number of Shapes in a group.
## Example
iex> Vivid.Group.init([Vivid.Point.init(1,1), Vivid.Point.init(2,2)])
...> |> Enum.count
2
"""
def count(%Group{shapes: shapes}), do: {:ok, Enum.count(shapes)}
@doc """
Returns whether the shape is a member of a group.
## Examples
iex> Vivid.Group.init([Vivid.Point.init(1,1)])
...> |> Enum.member?(Vivid.Point.init(1,1))
true
iex> Vivid.Group.init([Vivid.Point.init(1,1)])
...> |> Enum.member?(Vivid.Point.init(2,2))
false
"""
def member?(%Group{shapes: shapes}, shape), do: {:ok, Enum.member?(shapes, shape)}
@doc """
Reduce's the Path's shapes into an accumulator
## Examples
iex> Vivid.Group.init([Vivid.Point.init(1,2), Vivid.Point.init(2,4)]) |> Enum.reduce(%{}, fn (%Vivid.Point{x: x, y: y}, acc) -> Map.put(acc, x, y) end)
%{1 => 2, 2 => 4}
"""
def reduce(%Group{shapes: shapes}, acc, fun), do: Enumerable.MapSet.reduce(shapes, acc, fun)
end

56
lib/vivid/group.ex Normal file
View file

@ -0,0 +1,56 @@
defmodule Vivid.Group do
alias Vivid.Group
defstruct ~w(shapes)a
@moduledoc """
Represents a collection of shapes which can be Rasterized in a single pass.
"""
@doc """
Initialize a group either empty or from a list of shapes.
## Examples
iex> circle = Vivid.Circle.init(Vivid.Point.init(5,5), 5)
...> line = Vivid.Line.init(Vivid.Point.init(1,1), Vivid.Point.init(10,10))
...> Vivid.Group.init([circle, line])
%Vivid.Group{shapes: MapSet.new([
%Vivid.Circle{center: %Vivid.Point{x: 5, y: 5}, radius: 5},
%Vivid.Line{origin: %Vivid.Point{x: 1, y: 1}, termination: %Vivid.Point{x: 10, y: 10}}
])}
iex> Vivid.Group.init
%Vivid.Group{shapes: MapSet.new()}
"""
def init, do: %Group{shapes: MapSet.new()}
def init(shapes) do
%Group{shapes: MapSet.new(shapes)}
end
@doc """
Remove a shape from a Group
## Example
iex> line = Vivid.Line.init(Vivid.Point.init(1,1), Vivid.Point.init(10,10))
...> Vivid.Group.init([line])
...> |> Vivid.Group.delete(line)
%Vivid.Group{shapes: MapSet.new()}
"""
def delete(%Group{shapes: shapes}, shape), do: shapes |> MapSet.delete(shape) |> init
@doc """
Add a shape to a Group
## Example
iex> line = Vivid.Line.init(Vivid.Point.init(1,1), Vivid.Point.init(10,10))
...> Vivid.Group.init()
...> |> Vivid.Group.put(line)
%Vivid.Group{shapes: MapSet.new([
%Vivid.Line{origin: %Vivid.Point{x: 1, y: 1}, termination: %Vivid.Point{x: 10, y: 10}}
])}
"""
def put(%Group{shapes: shapes}, shape), do: shapes |> MapSet.put(shape) |> init
end

View file

@ -0,0 +1,31 @@
defimpl Vivid.Rasterize, for: Vivid.Group do
alias Vivid.{Group, Rasterize}
@moduledoc """
Rasterizes the Group into a sequence of points.
"""
@doc """
Convert Group into a set of points for display.
## Example
iex> path = Vivid.Path.init([Vivid.Point.init(1,1), Vivid.Point.init(1,3), Vivid.Point.init(3,3), Vivid.Point.init(3,1)])
...> Vivid.Group.init([path])
...> |> Vivid.Rasterize.rasterize
MapSet.new([
%Vivid.Point{x: 1, y: 1},
%Vivid.Point{x: 1, y: 2},
%Vivid.Point{x: 1, y: 3},
%Vivid.Point{x: 2, y: 3},
%Vivid.Point{x: 3, y: 1},
%Vivid.Point{x: 3, y: 2},
%Vivid.Point{x: 3, y: 3}
])
"""
def rasterize(%Group{shapes: shapes}) do
Enum.reduce(shapes, MapSet.new, fn(shape, acc) ->
MapSet.union(acc, Rasterize.rasterize(shape))
end)
end
end

View file

@ -0,0 +1,4 @@
defmodule Collectable.Vivid.GroupTest do
use ExUnit.Case
doctest Collectable.Vivid.Group
end

View file

@ -0,0 +1,4 @@
defmodule Enumerable.Vivid.GroupTest do
use ExUnit.Case
doctest Enumerable.Vivid.Group
end

View file

@ -0,0 +1,4 @@
defmodule Vivid.GroupTest do
use ExUnit.Case
doctest Vivid.Group
end

View file

@ -0,0 +1,4 @@
defmodule Vivid.Rasterize.GroupTest do
use ExUnit.Case
doctest Vivid.Rasterize.Vivid.Group
end