forked from MakieOrg/Makie.jl
-
Notifications
You must be signed in to change notification settings - Fork 0
/
units.jl
134 lines (111 loc) · 4.02 KB
/
units.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#########
## Move attributes into certain unit spaces
# Future:
# Every plot / scene axis will hold a space attribute
# with the following allowed (per axis):
# (may not actually be a type hierarchy, just here for illustration)
# abstract type DataSpace end
# abstract type DisplaySpace end
# #...
# struct Log <: DataSpace end
# struct Polar <: DataSpace end
# struct GeoProjection <: DataSpace end
# # and more!
# #...
# struct Pixel <: DisplaySpace end
# struct DPI <: DisplaySpace end
# struct DIP <: DisplaySpace end
#########
function to_screen(scene::Scene, mpos)
return Point2f(mpos) .- Point2f(minimum(viewport(scene)[]))
end
number(x::Unit) = x.value
number(x) = x
Base.:(*)(a::T, b::Number) where {T<:Unit} = basetype(T)(number(a) * b)
Base.:(*)(a::Number, b::T) where {T<:Unit} = basetype(T)(a * number(b))
Base.convert(::Type{T}, x::Unit) where T<:Number = convert(T, number(x))
"""
Unit space of the scene it's displayed on.
Also referred to as data units
"""
struct SceneSpace{T} <: Unit{T}
value::T
end
"""
https://en.wikipedia.org/wiki/Device-independent_pixel
A device-independent pixel (also: density-independent pixel, dip, dp) is a
physical unit of measurement based on a coordinate system held by a
computer and represents an abstraction of a pixel for use by an
application that an underlying system then converts to physical pixels.
"""
struct DeviceIndependentPixel{T <: Number} <: Unit{T}
value::T
end
basetype(::Type{<: DeviceIndependentPixel}) = DeviceIndependentPixel
const DIP = DeviceIndependentPixel
const dip = DIP(1)
const dip_in_millimeter = 0.15875
const dip_in_inch = 1/160
basetype(::Type{<: Pixel}) = Pixel
"""
Millimeter on screen. This unit respects the dimension and pixel density of the screen
to represent millimeters on the screen. This is the must use unit for layouting,
that needs to look the same on all kind of screens. Similar as with the `Pixel` unit,
a camera can change the actually displayed dimensions of any object using the millimeter unit.
"""
struct Millimeter{T} <: Unit{T}
value::T
end
basetype(::Type{<: Millimeter}) = Millimeter
const mm = Millimeter(1)
Base.show(io::IO, x::DIP) = print(io, number(x), "dip")
Base.:(*)(a::Number, b::DIP) = DIP(a * number(b))
dpi(scene::Scene) = events(scene).window_dpi[]
function pixel_per_mm(scene)
dpi(scene) ./ 25.4
end
function Base.convert(::Type{<: Millimeter}, scene::Scene, x::SceneSpace)
pixel = convert(Pixel, scene, x)
Millimeter(number(pixel_per_mm(scene) / pixel))
end
function Base.convert(::Type{<: SceneSpace}, scene::Scene, x::DIP)
mm = convert(Millimeter, scene, x)
SceneSpace(number(mm * dip_in_millimeter))
end
function Base.convert(::Type{<: Millimeter}, scene::Scene, x::DIP)
Millimeter(number(x * dip_in_millimeter))
end
function Base.convert(::Type{<: Pixel}, scene::Scene, x::Millimeter)
px = pixel_per_mm(scene) * x
Pixel(number(px))
end
function Base.convert(::Type{<: Pixel}, scene::Scene, x::DIP)
inch = (x * dip_in_inch)
dots = dpi(scene) * inch
Pixel(number(dots))
end
function Base.convert(::Type{<: SceneSpace}, scene::Scene, x::Vec{2, <:Pixel})
zero = to_world(scene, to_screen(scene, Point2f(0)))
s = to_world(scene, to_screen(scene, number.(Point(x))))
SceneSpace.(Vec(s .- zero))
end
function Base.convert(::Type{<: SceneSpace}, scene::Scene, x::Pixel)
zero = to_world(scene, to_screen(scene, Point2f(0)))
s = to_world(scene, to_screen(scene, Point2f(number(x), 0.0)))
SceneSpace(norm(s .- zero))
end
function Base.convert(::Type{<: SceneSpace}, scene::Scene, x::Millimeter)
pix = convert(Pixel, scene, x)
(SceneSpace, mm)
end
to_2d_scale(x::Pixel) = Vec2f(number(x))
to_2d_scale(x::Tuple{<:Pixel, <:Pixel}) = Vec2f(number.(x))
to_2d_scale(x::VecTypes{2, <:Pixel}) = Vec2f(number.(x))
# Exports of units
export px
########################################
spaces() = (:data, :pixel, :relative, :clip)
is_data_space(space) = space === :data
is_pixel_space(space) = space === :pixel
is_relative_space(space) = space === :relative
is_clip_space(space) = space === :clip