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

[RFC] Generalize some fallbacks #29

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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
66 changes: 40 additions & 26 deletions src/Graphics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -190,14 +190,14 @@ end

Get the horizontal length of `obj`.
"""
width(bb::BoundingBox) = bb.xmax - bb.xmin # TODO: generalization with xmax()/xmin()
width(obj) = xmax(obj) - xmin(obj)

"""
hieght(obj) -> h

Get the vertical length of `obj`.
"""
height(bb::BoundingBox) = bb.ymax - bb.ymin # TODO: generalization with ymax()/ymin()
height(obj) = ymax(obj) - ymin(obj)

"""
diagonal(obj) -> diag
Expand Down Expand Up @@ -410,9 +410,9 @@ abstract type GraphicsDevice end
Create a new `GraphicContext`.
"""
@mustimplement creategc(gd::GraphicsDevice)
xmin(g::GraphicsDevice) = 0 # FIXME: use the same type as `xmax`
xmin(g::GraphicsDevice) = zero(typeof(width(g)))
xmax(g::GraphicsDevice) = width(g)
ymin(g::GraphicsDevice) = 0 # FIXME: use the same type as `ymax`
ymin(g::GraphicsDevice) = zero(typeof(height(g)))
ymax(g::GraphicsDevice) = height(g)

"""
Expand Down Expand Up @@ -555,42 +555,54 @@ after any existing transformation.
@mustimplement translate(gc::GraphicsContext, ::Real, ::Real)

"""
user_to_device!(gc::GraphicsContext, c::Vector{Float64})
user_to_device!(gc::GraphicsContext, c::AbstractVector)

Transform a coordinate `c` from the user space to the device space.

See also: [`user_to_device`](@ref), [`device_to_user!`](@ref)
"""
user_to_device!(gc::GraphicsContext, c::Vector{Float64}) = c # TODO: generalization
function user_to_device!(gc::GraphicsContext, c::AbstractVector{T}) where T <: Real
length(c) == 2 || throw(ArgumentError("Only 2-D vectors are supported."))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
length(c) == 2 || throw(ArgumentError("Only 2-D vectors are supported."))
length(c) == 2 || throw(ArgumentError("Only length-2 vectors are supported."))

@inbounds c[1], c[2] = user_to_device(gc, Float64(c[1]), Float64(c[2]))
end
user_to_device!(gc::GraphicsContext, c::Vector{Float64}) = c

"""
device_to_user!(gc::GraphicsContext, c::Vector{Float64})
device_to_user!(gc::GraphicsContext, c::AbstractVector)

Transform a coordinate `c` from the device space to the user space.

See also: [`device_to_user`](@ref), [`user_to_device!`](@ref)
"""
device_to_user!(gc::GraphicsContext, c::Vector{Float64}) = c # TODO: generalization
function device_to_user!(gc::GraphicsContext, c::AbstractVector{T}) where T <: Real
length(c) == 2 || throw(ArgumentError("Only 2-D vectors are supported."))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
length(c) == 2 || throw(ArgumentError("Only 2-D vectors are supported."))
length(c) == 2 || throw(ArgumentError("Only length-2 vectors are supported."))

@inbounds c[1], c[2] = user_to_device(gc, Float64(c[1]), Float64(c[2]))
end
device_to_user!(gc::GraphicsContext, c::Vector{Float64}) = c

"""
user_to_device_distance!(gc::GraphicsContext, d::Vector{Float64})
user_to_device_distance!(gc::GraphicsContext, d::AbstractVector)

Transform a distance vector `d` from the user space to the device space. This
function is similar to the [`device_to_user!`](@ref) except that the translation
components will be cancelled.
"""
user_to_device_distance!(gc::GraphicsContext, c::Vector{Float64}) = c # TODO: generalization
function user_to_device_distance!(gc::GraphicsContext, d::AbstractVector{T}) where T <: Real
user_to_device!(gc, d)
d .-= user_to_device(gc, zero(T), zero(T))
end

"""
device_to_user_distance!(gc::GraphicsContext, d::Vector{Float64})
device_to_user_distance!(gc::GraphicsContext, d::AbstractVector)

Transform a distance vector `d` from the device space to the user space. This
function is similar to the [`user_to_device!`](@ref) except that the translation
components will be cancelled.
"""
device_to_user_distance!(gc::GraphicsContext, c::Vector{Float64}) = c # TODO: generalization

const d2ubuf = zeros(2)
function device_to_user_distance!(gc::GraphicsContext, d::AbstractVector{T}) where T <: Real
device_to_user!(gc, d)
d .-= device_to_user(gc, zero(T), zero(T))
end

"""
user_to_device(gc::GraphicsContext, x, y) -> (xd, yd)
Expand All @@ -600,11 +612,10 @@ Transform a user space coordinate `(x, y)` to the device space coordinate

See also: [`user_to_device!`](@ref), [`device_to_user`](@ref)
"""
function user_to_device(gc::GraphicsContext, x::Real, y::Real) # FIXME: avoid use of global variable
d2ubuf[1] = x
d2ubuf[2] = y
user_to_device!(gc, d2ubuf)
d2ubuf[1], d2ubuf[2]
function user_to_device(gc::GraphicsContext, x::Real, y::Real)
v = [x, y]
user_to_device!(gc, v)
@inbounds (v[1], v[2])
end

"""
Expand All @@ -615,11 +626,10 @@ Transform a device space coordinate `(x, y)` to the user space coordinate

See also: [`device_to_user!`](@ref), [`user_to_device`](@ref)
"""
function device_to_user(gc::GraphicsContext, x::Real, y::Real) # FIXME: avoid use of global variable
d2ubuf[1] = x
d2ubuf[2] = y
device_to_user!(gc, d2ubuf)
d2ubuf[1], d2ubuf[2]
function device_to_user(gc::GraphicsContext, x::Real, y::Real)
v = [x, y]
device_to_user!(gc, v)
@inbounds (v[1], v[2])
end

# drawing and properties
Expand Down Expand Up @@ -672,8 +682,12 @@ source color.
@mustimplement set_source(gc::GraphicsContext, src)

function set_source(gc::GraphicsContext, c::Color)
rgb = convert(RGB, c)
set_source_rgb(gc, rgb.r, rgb.g, rgb.b)
c isa AbstractRGB && return set_source_rgb(gc, red(c), green(c), blue(c))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe slightly cleaner with dispatch but no big deal either way

Copy link
Contributor Author

@kimikage kimikage Feb 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I almost forgot the original intent, but the specialization can introduce ambiguity in the backend implementations.

Of course, it is possible to dispatch "private" methods.

set_source(gc, convert(RGB, c))
end
function set_source(gc::GraphicsContext, c::TransparentColor)
c isa TransparentRGB && return set_source_rgba(gc, red(c), green(c), blue(c), alpha(c))
set_source(gc, convert(ARGB, c))
end

"""
Expand Down