Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shape hierarchy #29

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 36 additions & 15 deletions src/core.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,13 @@ struct Point <: Drawable
y::Int
end

abstract type Line <: Drawable end
abstract type Circle <: Drawable end
abstract type AbstractPath <: Drawable end
abstract type AbstractLine <: Drawable end
abstract type AbstractShape <: Drawable end

abstract type AbstractPolygon <: AbstractShape end
abstract type AbstractEllipse <: AbstractShape end
abstract type AbstractCircle <: AbstractEllipse end


"""
Expand All @@ -24,7 +29,7 @@ abstract type Circle <: Drawable end
A `Drawable` infinite length line passing through the two points
`p1` and `p2`.
"""
struct LineTwoPoints <: Line
struct LineTwoPoints <: AbstractLine
p1::Point
p2::Point
end
Expand All @@ -36,7 +41,7 @@ A `Drawable` infinte length line having perpendicular length `ρ` from
origin and angle `θ` between the perpendicular and x-axis

"""
struct LineNormal{T<:Real, U<:Real} <: Line
struct LineNormal{T<:Real, U<:Real} <: AbstractLine
ρ::T
θ::U
end
Expand All @@ -46,7 +51,7 @@ end

A `Drawable` circle passing through points `p1`, `p2` and `p3`
"""
struct CircleThreePoints <: Circle
struct CircleThreePoints <: AbstractCircle
p1::Point
p2::Point
p3::Point
Expand All @@ -57,7 +62,7 @@ end

A `Drawable` circle having center `center` and radius `ρ`
"""
struct CirclePointRadius{T<:Real} <: Circle
struct CirclePointRadius{T<:Real} <: AbstractCircle
center::Point
ρ::T
end
Expand All @@ -67,7 +72,7 @@ end

A `Drawable` finite length line between `p1` and `p2`
"""
struct LineSegment <: Drawable
struct LineSegment <: AbstractLine
p1::Point
p2::Point
end
Expand All @@ -80,7 +85,7 @@ of points in `[point]`.
!!! note
This will create a non-closed path. For a closed path, see `Polygon`
"""
struct Path <: Drawable
struct Path <: AbstractPath
vertices::Vector{Point}
end

Expand All @@ -90,7 +95,7 @@ end
A `Drawable` ellipse with center `center` and parameters `ρx` and `ρy`

"""
struct Ellipse{T<:Real, U<:Real} <: Drawable
struct Ellipse{T<:Real, U<:Real} <: AbstractEllipse
center::Point
ρx::T
ρy::U
Expand All @@ -104,7 +109,7 @@ consecutive points in `[vertex]` along with the first and last point.
!!! note
This will create a closed path. For a non-closed path, see `Path`
"""
struct Polygon <: Drawable
struct Polygon <: AbstractPolygon
vertices::Vector{Point}
end

Expand All @@ -120,7 +125,7 @@ A `Drawable` regular polygon.
* `θ::Real` : orientation of the polygon w.r.t x-axis (in radians)

"""
struct RegularPolygon{T<:Real, U<:Real} <: Drawable
struct RegularPolygon{T<:Real, U<:Real} <: AbstractPolygon
center::Point
side_count::Int
side_length::T
Expand All @@ -131,7 +136,7 @@ end
cross = Cross(c, range::UnitRange{Int})
A `Drawable` cross passing through the point `c` with arms ranging across `range`.
"""
struct Cross <: Drawable
struct Cross <: AbstractPath
c::Point
range::UnitRange{Int}
end
Expand Down Expand Up @@ -182,8 +187,24 @@ Point(τ::Tuple{Int, Int}) = Point(τ...)
Point(p::CartesianIndex) = Point(p[2], p[1])

function draw!(img::AbstractArray{T,2}, point::Point, color::T) where T<:Colorant
if checkbounds(Bool, img, point.y, point.x)
img[point.y, point.x] = color
end
drawifinbounds!(img, point, color)
end

"""

img_new = drawifinbounds!(img, y, x, color)
img_new = drawifinbounds!(img, Point, color)
img_new = drawifinbounds!(img, CartesianIndex, color)

Draws a single point after checkbounds() for coordinate in the image.
Color Defaults to oneunit(T)

"""

drawifinbounds!(img::AbstractArray{T,2}, p::Point, color::T = oneunit(T)) where {T<:Colorant} = drawifinbounds!(img, p.y, p.x, color)
drawifinbounds!(img::AbstractArray{T,2}, p::CartesianIndex{2}, color::T = oneunit(T)) where {T<:Colorant} = drawifinbounds!(img, Point(p), color)

function drawifinbounds!(img::AbstractArray{T,2}, y::Int, x::Int, color::T) where {T<:Colorant}
if checkbounds(Bool, img, y, x) img[y, x] = color end
img
end
4 changes: 2 additions & 2 deletions src/cross.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ Cross(c, arm::Int) = Cross(c, -arm:arm)

function draw!(img::AbstractArray{T, 2}, cross::Cross, color::T) where T<:Colorant
for Δx in cross.range
img[cross.c.y, cross.c.x + Δx] = color
drawifinbounds!(img, cross.c.y, cross.c.x + Δx, color)
end
for Δy in cross.range
img[cross.c.y + Δy, cross.c.x] = color
drawifinbounds!(img, cross.c.y + Δy, cross.c.x, color)
end
img
end
8 changes: 4 additions & 4 deletions src/ellipse2d.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ function draw!(img::AbstractArray{T, 2}, ellipse::Ellipse, color::T) where T<:Co
end
end
for (yi, xi) in zip(ys, xs)
img[yi, xi] = color
img[2 * ellipse.center.y - yi, xi] = color
img[yi, 2 * ellipse.center.x - xi] = color
img[2 * ellipse.center.y - yi, 2 * ellipse.center.x - xi] = color
drawifinbounds!(img, yi, xi, color)
drawifinbounds!(img,2 * ellipse.center.y - yi, xi, color)
drawifinbounds!(img,yi, 2 * ellipse.center.x - xi, color)
drawifinbounds!(img, 2 * ellipse.center.y - yi, 2 * ellipse.center.x - xi, color)
end
img
end
14 changes: 7 additions & 7 deletions src/line2d.jl
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ function bresenham(img::AbstractArray{T, 2}, y0::Int, x0::Int, y1::Int, x1::Int,
err = (dx > dy ? dx : -dy) / 2

while true
img[y0, x0] = color
drawifinbounds!(img, y0, x0, color)
(x0 != x1 || y0 != y1) || break
e2 = err
if e2 > -dx
Expand Down Expand Up @@ -125,9 +125,9 @@ function xiaolin_wu(img::AbstractArray{T, 2}, y0::Int, x0::Int, y1::Int, x1::Int
xpxl0 = xend
ypxl0 = trunc(Int, yend)
index = swapped ? CartesianIndex(xpxl0, ypxl0) : CartesianIndex(ypxl0, xpxl0)
if checkbounds(Bool, img, index) img[index] = T(rfpart(yend) * xgap) end
drawifinbounds!(img, index, T(rfpart(yend) * xgap))
index = swapped ? CartesianIndex(xpxl0, ypxl0 + 1) : CartesianIndex(ypxl0 + 1, xpxl0)
if checkbounds(Bool, img, index) img[index] = T(fpart(yend) * xgap) end
drawifinbounds!(img, index, T(fpart(yend) * xgap))
intery = yend + gradient

xend = round(Int, x1)
Expand All @@ -136,15 +136,15 @@ function xiaolin_wu(img::AbstractArray{T, 2}, y0::Int, x0::Int, y1::Int, x1::Int
xpxl1 = xend
ypxl1 = trunc(Int, yend)
index = swapped ? CartesianIndex(xpxl1, ypxl1) : CartesianIndex(ypxl1, xpxl1)
if checkbounds(Bool, img, index) img[index] = T(rfpart(yend) * xgap) end
drawifinbounds!(img, index, T(rfpart(yend) * xgap))
index = swapped ? CartesianIndex(xpxl1, ypxl1 + 1) : CartesianIndex(ypxl1 + 1, xpxl1)
if checkbounds(Bool, img, index) img[index] = T(fpart(yend) * xgap) end
drawifinbounds!(img, index, T(fpart(yend) * xgap))

for i in (xpxl0 + 1):(xpxl1 - 1)
index = swapped ? CartesianIndex(i, trunc(Int, intery)) : CartesianIndex(trunc(Int, intery), i)
if checkbounds(Bool, img, index) img[index] = T(rfpart(intery)) end
drawifinbounds!(img, index, T(rfpart(intery)))
index = swapped ? CartesianIndex(i, trunc(Int, intery) + 1) : CartesianIndex(trunc(Int, intery) + 1, i)
if checkbounds(Bool, img, index) img[index] = T(fpart(intery)) end
drawifinbounds!(img, index, T(fpart(intery)))
intery += gradient
end
img
Expand Down
16 changes: 2 additions & 14 deletions src/paths.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,10 @@ Path(v::AbstractVector{CartesianIndex{2}}) = Path([Point(p) for p in v])

function draw!(img::AbstractArray{T, 2}, path::Path, color::T) where T<:Colorant
vertices = [CartesianIndex(p.y, p.x) for p in path.vertices]
f = CartesianIndex(map(r->first(r)-1, axes(img)))
l = CartesianIndex(map(r->last(r), axes(img)))

if min(f,vertices[1])!=f || max(l,vertices[1])!=l
println(vertices[1])
error("Point coordinates out of range.")
end

for i in 1:length(vertices)-1
if min(f,vertices[i+1])==f && max(l,vertices[i+1])==l
draw!(img, LineSegment(vertices[i], vertices[i+1]), color)
else
println(vertices[i+1])
error("Point coordinates out of range.")
end
draw!(img, LineSegment(vertices[i], vertices[i+1]), color)
end
img
end

#Polygon methods
Expand Down
12 changes: 7 additions & 5 deletions test/paths.jl
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,14 @@ end
@test all(x->x==RGB{N0f8}(0,0,0), img[2,1:3])==true
@test img[2,4]==RGB{N0f8}(1,1,1)

img = zeros(Gray{N0f8},5,5)
invalid_points = [(6,1), (4,4), (1,7), (7,6)]
@test_throws ErrorException draw!(img, Path(invalid_points))
# No longer invalid, the program will draw what it can on the image

invalid_points = [(4,4), (1,7), (7,6)]
@test_throws ErrorException draw!(img, Path(invalid_points))
# img = zeros(Gray{N0f8},5,5)
# invalid_points = [(6,1), (4,4), (1,7), (7,6)]
# @test_throws ErrorException draw!(img, Path(invalid_points))
#
# invalid_points = [(4,4), (1,7), (7,6)]
# @test_throws ErrorException draw!(img, Path(invalid_points))
end

@testset "RegularPolygon" begin
Expand Down