Merge pull request #570 from tbreloff/sd/dev
refactors + rename for new GLWindow version
This commit is contained in:
commit
436ab89d2d
@ -1,4 +1,4 @@
|
|||||||
#=
|
``#=
|
||||||
TODO
|
TODO
|
||||||
* move all gl_ methods to GLPlot
|
* move all gl_ methods to GLPlot
|
||||||
* integrate GLPlot UI
|
* integrate GLPlot UI
|
||||||
@ -98,8 +98,33 @@ end
|
|||||||
# GLPlot.init()
|
# GLPlot.init()
|
||||||
# end
|
# end
|
||||||
const _glplot_deletes = []
|
const _glplot_deletes = []
|
||||||
|
|
||||||
|
function close_child_signals!(screen)
|
||||||
|
for child in screen.children
|
||||||
|
for (k, s) in child.inputs
|
||||||
|
empty!(s.actions)
|
||||||
|
end
|
||||||
|
for (k, cam) in child.cameras
|
||||||
|
for f in fieldnames(cam)
|
||||||
|
s = getfield(cam, f)
|
||||||
|
if isa(s, Signal)
|
||||||
|
close(s, false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
empty!(child.cameras)
|
||||||
|
close_child_signals!(child)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
function empty_screen!(screen)
|
function empty_screen!(screen)
|
||||||
if isempty(_glplot_deletes)
|
if isempty(_glplot_deletes)
|
||||||
|
close_child_signals!(screen)
|
||||||
|
empty!(screen)
|
||||||
|
empty!(screen.cameras)
|
||||||
|
for (k, s) in screen.inputs
|
||||||
|
empty!(s.actions)
|
||||||
|
end
|
||||||
empty!(screen)
|
empty!(screen)
|
||||||
else
|
else
|
||||||
for del_signal in _glplot_deletes
|
for del_signal in _glplot_deletes
|
||||||
@ -113,38 +138,55 @@ function poll_reactive()
|
|||||||
# run_till_now blocks when message queue is empty!
|
# run_till_now blocks when message queue is empty!
|
||||||
Base.n_avail(Reactive._messages) > 0 && Reactive.run_till_now()
|
Base.n_avail(Reactive._messages) > 0 && Reactive.run_till_now()
|
||||||
end
|
end
|
||||||
function create_window(plt::Plot{GLVisualizeBackend}, visible)
|
|
||||||
# init a screen
|
|
||||||
if isempty(GLVisualize.get_screens())
|
|
||||||
screen = GLVisualize.glscreen("Plots.jl", resolution = plt[:size], visible = visible)
|
|
||||||
Reactive.stop()
|
|
||||||
|
|
||||||
@async begin
|
|
||||||
while isopen(screen)
|
function get_plot_screen(list::Vector, name, result = [])
|
||||||
tic()
|
for elem in list
|
||||||
GLWindow.pollevents()
|
get_plot_screen(elem, name, result)
|
||||||
if Base.n_avail(Reactive._messages) > 0
|
|
||||||
poll_reactive()
|
|
||||||
poll_reactive() # two times for secondary signals
|
|
||||||
GLWindow.render_frame(screen)
|
|
||||||
GLWindow.swapbuffers(screen)
|
|
||||||
end
|
|
||||||
yield()
|
|
||||||
diff = (1/60) - toq()
|
|
||||||
while diff >= 0.001
|
|
||||||
tic()
|
|
||||||
sleep(0.001) # sleep for the minimal amount of time
|
|
||||||
diff -= toq()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
# empty message queue
|
|
||||||
poll_reactive()
|
|
||||||
GLWindow.destroy!(screen)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
screen = GLVisualize.current_screen()
|
|
||||||
empty_screen!(screen)
|
|
||||||
end
|
end
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
function get_plot_screen(screen, name, result = [])
|
||||||
|
if screen.name == name
|
||||||
|
push!(result, screen)
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
get_plot_screen(screen.children, name, result)
|
||||||
|
end
|
||||||
|
|
||||||
|
function create_window(plt::Plot{GLVisualizeBackend}, visible)
|
||||||
|
name = Symbol("Plots.jl")
|
||||||
|
# make sure we have any screen open
|
||||||
|
if isempty(GLVisualize.get_screens())
|
||||||
|
# create a fresh, new screen
|
||||||
|
screen = GLVisualize.glscreen(
|
||||||
|
"Plot",
|
||||||
|
resolution = plt[:size],
|
||||||
|
visible = visible
|
||||||
|
)
|
||||||
|
@async GLWindow.waiting_renderloop(screen)
|
||||||
|
end
|
||||||
|
# now lets get ourselves a permanent Plotting screen
|
||||||
|
plot_screens = get_plot_screen(GLVisualize.get_screens(), name)
|
||||||
|
screen = if isempty(plot_screens) # no screen with `name`
|
||||||
|
parent = GLVisualize.current_screen()
|
||||||
|
screen = GLWindow.Screen(
|
||||||
|
parent, area = map(GLWindow.zeroposition, parent.area),
|
||||||
|
name = name
|
||||||
|
)
|
||||||
|
for (k, s) in screen.inputs # copy signals, so we can clean them up better
|
||||||
|
screen.inputs[k] = map(identity, s)
|
||||||
|
end
|
||||||
|
screen
|
||||||
|
elseif length(plot_screens) == 1
|
||||||
|
plot_screens[1]
|
||||||
|
else
|
||||||
|
# okay this is silly! Lets see if we can. There is an ID we could use
|
||||||
|
# will not be fine for more than 255 screens though -.-.
|
||||||
|
error("multiple Plot screens. Please don't use any screen with the name Plots.jl")
|
||||||
|
end
|
||||||
|
# Since we own this window, we can do deep cleansing
|
||||||
|
empty_screen!(screen)
|
||||||
plt.o = screen
|
plt.o = screen
|
||||||
GLWindow.set_visibility!(screen, visible)
|
GLWindow.set_visibility!(screen, visible)
|
||||||
resize!(screen, plt[:size]...)
|
resize!(screen, plt[:size]...)
|
||||||
@ -161,6 +203,8 @@ const _gl_marker_map = KW(
|
|||||||
:xcross => '❌',
|
:xcross => '❌',
|
||||||
:utriangle => '▲',
|
:utriangle => '▲',
|
||||||
:dtriangle => '▼',
|
:dtriangle => '▼',
|
||||||
|
:ltriangle => '◀',
|
||||||
|
:rtriangle => '▶',
|
||||||
:pentagon => '⬟',
|
:pentagon => '⬟',
|
||||||
:octagon => '⯄',
|
:octagon => '⯄',
|
||||||
:star4 => '✦',
|
:star4 => '✦',
|
||||||
@ -170,6 +214,7 @@ const _gl_marker_map = KW(
|
|||||||
:hline => '━',
|
:hline => '━',
|
||||||
:+ => '+',
|
:+ => '+',
|
||||||
:x => 'x',
|
:x => 'x',
|
||||||
|
:circle => '●'
|
||||||
)
|
)
|
||||||
|
|
||||||
function gl_marker(shape)
|
function gl_marker(shape)
|
||||||
@ -185,6 +230,12 @@ function gl_marker(shape::Shape)
|
|||||||
GeometryTypes.GLNormalMesh(points)
|
GeometryTypes.GLNormalMesh(points)
|
||||||
end
|
end
|
||||||
# create a marker/shape type
|
# create a marker/shape type
|
||||||
|
function gl_marker(shape::Vector{Symbol})
|
||||||
|
String(map(shape) do sym
|
||||||
|
get(_gl_marker_map, sym, '●')
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
function gl_marker(shape::Symbol)
|
function gl_marker(shape::Symbol)
|
||||||
if shape == :rect
|
if shape == :rect
|
||||||
GeometryTypes.HyperRectangle(Vec2f0(0), Vec2f0(1))
|
GeometryTypes.HyperRectangle(Vec2f0(0), Vec2f0(1))
|
||||||
@ -209,6 +260,14 @@ function extract_limits(sp, d, kw_args)
|
|||||||
nothing
|
nothing
|
||||||
end
|
end
|
||||||
|
|
||||||
|
to_vec{T <: FixedVector}(::Type{T}, vec::T) = vec
|
||||||
|
to_vec{T <: FixedVector}(::Type{T}, s::Number) = T(s)
|
||||||
|
|
||||||
|
to_vec{T <: FixedVector{2}}(::Type{T}, vec::FixedVector{3}) = T(vec[1], vec[2])
|
||||||
|
to_vec{T <: FixedVector{3}}(::Type{T}, vec::FixedVector{2}) = T(vec[1], vec[2], 0)
|
||||||
|
|
||||||
|
to_vec{T <: FixedVector}(::Type{T}, vecs::AbstractVector) = map(x-> to_vec(T, x), vecs)
|
||||||
|
|
||||||
function extract_marker(d, kw_args)
|
function extract_marker(d, kw_args)
|
||||||
dim = Plots.is3d(d) ? 3 : 2
|
dim = Plots.is3d(d) ? 3 : 2
|
||||||
scaling = dim == 3 ? 0.003 : 2
|
scaling = dim == 3 ? 0.003 : 2
|
||||||
@ -222,13 +281,11 @@ function extract_marker(d, kw_args)
|
|||||||
dim = isa(kw_args[:primitive], GLVisualize.Sprites) ? 2 : 3
|
dim = isa(kw_args[:primitive], GLVisualize.Sprites) ? 2 : 3
|
||||||
if haskey(d, :markersize)
|
if haskey(d, :markersize)
|
||||||
msize = d[:markersize]
|
msize = d[:markersize]
|
||||||
if isa(msize, AbstractArray)
|
kw_args[:scale] = to_vec(GeometryTypes.Vec{dim, Float32}, msize .* scaling)
|
||||||
kw_args[:scale] = map(x->GeometryTypes.Vec{dim, Float32}(x*scaling), msize)
|
end
|
||||||
else
|
if haskey(d, :offset)
|
||||||
kw_args[:scale] = GeometryTypes.Vec{dim, Float32}(msize*scaling)
|
kw_args[:offset] = d[:offset]
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# get the color
|
# get the color
|
||||||
key = :markercolor
|
key = :markercolor
|
||||||
haskey(d, key) || return
|
haskey(d, key) || return
|
||||||
@ -259,6 +316,7 @@ end
|
|||||||
function _extract_surface(d::AbstractArray)
|
function _extract_surface(d::AbstractArray)
|
||||||
d
|
d
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO when to transpose??
|
# TODO when to transpose??
|
||||||
function extract_surface(d)
|
function extract_surface(d)
|
||||||
map(_extract_surface, (d[:x], d[:y], d[:z]))
|
map(_extract_surface, (d[:x], d[:y], d[:z]))
|
||||||
@ -271,7 +329,7 @@ function extract_points(d)
|
|||||||
array = (d[:x], d[:y], d[:z])[1:dim]
|
array = (d[:x], d[:y], d[:z])[1:dim]
|
||||||
topoints(Point{dim, Float32}, array)
|
topoints(Point{dim, Float32}, array)
|
||||||
end
|
end
|
||||||
function make_gradient{C<:Colorant}(grad::Vector{C})
|
function make_gradient{C <: Colorant}(grad::Vector{C})
|
||||||
grad
|
grad
|
||||||
end
|
end
|
||||||
function make_gradient(grad::ColorGradient)
|
function make_gradient(grad::ColorGradient)
|
||||||
@ -317,9 +375,10 @@ end
|
|||||||
function extract_stroke(d, kw_args)
|
function extract_stroke(d, kw_args)
|
||||||
extract_c(d, kw_args, :line)
|
extract_c(d, kw_args, :line)
|
||||||
if haskey(d, :linewidth)
|
if haskey(d, :linewidth)
|
||||||
kw_args[:thickness] = d[:linewidth]*3
|
kw_args[:thickness] = d[:linewidth] * 3
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function extract_color(d, sym)
|
function extract_color(d, sym)
|
||||||
d[Symbol("$(sym)color")]
|
d[Symbol("$(sym)color")]
|
||||||
end
|
end
|
||||||
@ -357,6 +416,7 @@ end
|
|||||||
|
|
||||||
dist(a, b) = abs(a-b)
|
dist(a, b) = abs(a-b)
|
||||||
mindist(x, a, b) = min(dist(a, x), dist(b, x))
|
mindist(x, a, b) = min(dist(a, x), dist(b, x))
|
||||||
|
|
||||||
function gappy(x, ps)
|
function gappy(x, ps)
|
||||||
n = length(ps)
|
n = length(ps)
|
||||||
x <= first(ps) && return first(ps) - x
|
x <= first(ps) && return first(ps) - x
|
||||||
@ -370,7 +430,7 @@ function gappy(x, ps)
|
|||||||
return last(ps) - x
|
return last(ps) - x
|
||||||
end
|
end
|
||||||
function ticks(points, resolution)
|
function ticks(points, resolution)
|
||||||
Float16[gappy(x, points) for x=linspace(first(points),last(points), resolution)]
|
Float16[gappy(x, points) for x = linspace(first(points),last(points), resolution)]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@ -405,9 +465,11 @@ function extract_linestyle(d, kw_args)
|
|||||||
extract_c(d, kw_args, :line)
|
extract_c(d, kw_args, :line)
|
||||||
nothing
|
nothing
|
||||||
end
|
end
|
||||||
|
|
||||||
function hover(to_hover::Vector, to_display, window)
|
function hover(to_hover::Vector, to_display, window)
|
||||||
hover(to_hover[], to_display, window)
|
hover(to_hover[], to_display, window)
|
||||||
end
|
end
|
||||||
|
|
||||||
function get_cam(x)
|
function get_cam(x)
|
||||||
if isa(x, GLAbstraction.Context)
|
if isa(x, GLAbstraction.Context)
|
||||||
return get_cam(x.children)
|
return get_cam(x.children)
|
||||||
@ -418,6 +480,7 @@ function get_cam(x)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function hover(to_hover, to_display, window)
|
function hover(to_hover, to_display, window)
|
||||||
if isa(to_hover, GLAbstraction.Context)
|
if isa(to_hover, GLAbstraction.Context)
|
||||||
return hover(to_hover.children, to_display, window)
|
return hover(to_hover.children, to_display, window)
|
||||||
@ -436,7 +499,7 @@ function hover(to_hover, to_display, window)
|
|||||||
GLAbstraction.PerspectiveCamera(
|
GLAbstraction.PerspectiveCamera(
|
||||||
popup.inputs, Vec3f0(3), Vec3f0(0),
|
popup.inputs, Vec3f0(3), Vec3f0(0),
|
||||||
keep = Signal(false),
|
keep = Signal(false),
|
||||||
theta = Signal(Vec3f0(0)), trans= Signal(Vec3f0(0))
|
theta = Signal(Vec3f0(0)), trans = Signal(Vec3f0(0))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -453,12 +516,12 @@ function hover(to_hover, to_display, window)
|
|||||||
else
|
else
|
||||||
cam.projectiontype.value = GLVisualize.ORTHOGRAPHIC
|
cam.projectiontype.value = GLVisualize.ORTHOGRAPHIC
|
||||||
end
|
end
|
||||||
GLVisualize._view(robj, popup, camera=cam)
|
GLVisualize._view(robj, popup, camera = cam)
|
||||||
bb = GLAbstraction.boundingbox(robj).value
|
bb = GLAbstraction.boundingbox(robj).value
|
||||||
mini = minimum(bb)
|
mini = minimum(bb)
|
||||||
w = GeometryTypes.widths(bb)
|
w = GeometryTypes.widths(bb)
|
||||||
wborder = w*0.08f0 #8 percent border
|
wborder = w * 0.08f0 #8 percent border
|
||||||
bb = GeometryTypes.AABB{Float32}(mini-wborder, w+2f0*wborder)
|
bb = GeometryTypes.AABB{Float32}(mini - wborder, w + 2 * wborder)
|
||||||
GLAbstraction.center!(cam, bb)
|
GLAbstraction.center!(cam, bb)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
@ -467,7 +530,7 @@ function hover(to_hover, to_display, window)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function extract_extrema(d, kw_args)
|
function extract_extrema(d, kw_args)
|
||||||
xmin,xmax = extrema(d[:x]); ymin,ymax = extrema(d[:y])
|
xmin, xmax = extrema(d[:x]); ymin, ymax = extrema(d[:y])
|
||||||
kw_args[:primitive] = GeometryTypes.SimpleRectangle{Float32}(xmin, ymin, xmax-xmin, ymax-ymin)
|
kw_args[:primitive] = GeometryTypes.SimpleRectangle{Float32}(xmin, ymin, xmax-xmin, ymax-ymin)
|
||||||
nothing
|
nothing
|
||||||
end
|
end
|
||||||
@ -498,6 +561,7 @@ function extract_colornorm(d, kw_args)
|
|||||||
kw_args[:intensity] = map(Float32, collect(z))
|
kw_args[:intensity] = map(Float32, collect(z))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function extract_gradient(d, kw_args, sym)
|
function extract_gradient(d, kw_args, sym)
|
||||||
key = Symbol("$(sym)color")
|
key = Symbol("$(sym)color")
|
||||||
haskey(d, key) || return
|
haskey(d, key) || return
|
||||||
@ -507,6 +571,7 @@ function extract_gradient(d, kw_args, sym)
|
|||||||
kw_args[:color_map] = c
|
kw_args[:color_map] = c
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
function extract_c(d, kw_args, sym)
|
function extract_c(d, kw_args, sym)
|
||||||
key = Symbol("$(sym)color")
|
key = Symbol("$(sym)color")
|
||||||
haskey(d, key) || return
|
haskey(d, key) || return
|
||||||
@ -568,20 +633,24 @@ function align_offset(startpos, lastpos, atlas, rscale, font, align)
|
|||||||
error("Align $align not known")
|
error("Align $align not known")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function align_offset(startpos, lastpos, atlas, rscale, font, align::Vec)
|
function align_offset(startpos, lastpos, atlas, rscale, font, align::Vec)
|
||||||
xscale, yscale = GLVisualize.glyph_scale!('X', rscale)
|
xscale, yscale = GLVisualize.glyph_scale!('X', rscale)
|
||||||
xmove = (lastpos-startpos)[1] + xscale
|
xmove = (lastpos-startpos)[1] + xscale
|
||||||
return -Vec2f0(xmove, yscale) .* align
|
return -Vec2f0(xmove, yscale) .* align
|
||||||
end
|
end
|
||||||
|
|
||||||
function alignment2num(x::Symbol)
|
function alignment2num(x::Symbol)
|
||||||
(x in (:hcenter, :vcenter)) && return 0.5
|
(x in (:hcenter, :vcenter)) && return 0.5
|
||||||
(x in (:left, :bottom)) && return 0.0
|
(x in (:left, :bottom)) && return 0.0
|
||||||
(x in (:right, :top)) && return 1.0
|
(x in (:right, :top)) && return 1.0
|
||||||
0.0 # 0 default, or better to error?
|
0.0 # 0 default, or better to error?
|
||||||
end
|
end
|
||||||
|
|
||||||
function alignment2num(font::Plots.Font)
|
function alignment2num(font::Plots.Font)
|
||||||
Vec2f0(map(alignment2num, (font.halign, font.valign)))
|
Vec2f0(map(alignment2num, (font.halign, font.valign)))
|
||||||
end
|
end
|
||||||
|
|
||||||
pointsize(font) = font.pointsize * 2
|
pointsize(font) = font.pointsize * 2
|
||||||
|
|
||||||
function draw_ticks(
|
function draw_ticks(
|
||||||
@ -627,16 +696,18 @@ function draw_ticks(
|
|||||||
end
|
end
|
||||||
text, positions, offsets
|
text, positions, offsets
|
||||||
end
|
end
|
||||||
|
|
||||||
function text(position, text, kw_args)
|
function text(position, text, kw_args)
|
||||||
text_align = alignment2num(text.font)
|
text_align = alignment2num(text.font)
|
||||||
startpos = Vec2f0(position)
|
startpos = Vec2f0(position)
|
||||||
atlas = GLVisualize.get_texture_atlas()
|
atlas = GLVisualize.get_texture_atlas()
|
||||||
font = GLVisualize.defaultfont()
|
font = GLVisualize.defaultfont()
|
||||||
rscale = kw_args[:relative_scale]
|
rscale = kw_args[:relative_scale]
|
||||||
m = Reactive.value(kw_args[:model])
|
|
||||||
position = GLVisualize.calc_position(text.str, startpos, rscale, font, atlas)
|
position = GLVisualize.calc_position(text.str, startpos, rscale, font, atlas)
|
||||||
offset = GLVisualize.calc_offset(text.str, rscale, font, atlas)
|
offset = GLVisualize.calc_offset(text.str, rscale, font, atlas)
|
||||||
alignoff = align_offset(startpos, last(position), atlas, rscale, font, text_align)
|
alignoff = align_offset(startpos, last(position), atlas, rscale, font, text_align)
|
||||||
|
|
||||||
map!(position) do pos
|
map!(position) do pos
|
||||||
pos .+ alignoff
|
pos .+ alignoff
|
||||||
end
|
end
|
||||||
@ -913,12 +984,44 @@ end
|
|||||||
|
|
||||||
# ----------------------------------------------------------------
|
# ----------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
function scale_for_annotations!(series::Series, scaletype::Symbol = :pixels)
|
||||||
|
anns = series[:series_annotations]
|
||||||
|
if anns != nothing && !isnull(anns.baseshape)
|
||||||
|
# we use baseshape to overwrite the markershape attribute
|
||||||
|
# with a list of custom shapes for each
|
||||||
|
msw, msh = anns.scalefactor
|
||||||
|
offsets = Array(Vec2f0, length(anns.strs))
|
||||||
|
series[:markersize] = map(1:length(anns.strs)) do i
|
||||||
|
str = cycle(anns.strs, i)
|
||||||
|
# get the width and height of the string (in mm)
|
||||||
|
sw, sh = text_size(str, anns.font.pointsize)
|
||||||
|
|
||||||
|
# how much to scale the base shape?
|
||||||
|
# note: it's a rough assumption that the shape fills the unit box [-1,-1,1,1],
|
||||||
|
# so we scale the length-2 shape by 1/2 the total length
|
||||||
|
xscale = 0.5to_pixels(sw) * 1.8
|
||||||
|
yscale = 0.5to_pixels(sh) * 1.8
|
||||||
|
|
||||||
|
# we save the size of the larger direction to the markersize list,
|
||||||
|
# and then re-scale a copy of baseshape to match the w/h ratio
|
||||||
|
s = Vec2f0(xscale, yscale)
|
||||||
|
offsets[i] = -s
|
||||||
|
s
|
||||||
|
end
|
||||||
|
series[:offset] = offsets
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function _display(plt::Plot{GLVisualizeBackend}, visible = true)
|
function _display(plt::Plot{GLVisualizeBackend}, visible = true)
|
||||||
screen = create_window(plt, visible)
|
screen = create_window(plt, visible)
|
||||||
sw, sh = plt[:size]
|
sw, sh = plt[:size]
|
||||||
sw, sh = sw*px, sh*px
|
sw, sh = sw*px, sh*px
|
||||||
|
|
||||||
# TODO: use plt.subplots... plt.spmap can't be trusted
|
|
||||||
for sp in plt.subplots
|
for sp in plt.subplots
|
||||||
_3d = Plots.is3d(sp)
|
_3d = Plots.is3d(sp)
|
||||||
# camera = :perspective
|
# camera = :perspective
|
||||||
@ -938,20 +1041,16 @@ function _display(plt::Plot{GLVisualizeBackend}, visible = true)
|
|||||||
theta = _3d ? nothing : Signal(Vec3f0(0)) # surpress rotation for 2D (nothing will get usual rotation controle)
|
theta = _3d ? nothing : Signal(Vec3f0(0)) # surpress rotation for 2D (nothing will get usual rotation controle)
|
||||||
GLAbstraction.PerspectiveCamera(
|
GLAbstraction.PerspectiveCamera(
|
||||||
sp_screen.inputs, Vec3f0(3), Vec3f0(0),
|
sp_screen.inputs, Vec3f0(3), Vec3f0(0),
|
||||||
keep=inside, theta=theta
|
keep = inside, theta = theta
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
rel_plotarea = Plots.bbox_to_pcts(plotarea(sp), sw, sh)
|
rel_plotarea = Plots.bbox_to_pcts(plotarea(sp), sw, sh)
|
||||||
model_m = map(Plots.to_modelmatrix, screen.area, sub_area, Signal(rel_plotarea), Signal(sp))
|
model_m = map(Plots.to_modelmatrix,
|
||||||
for ann in sp[:annotations]
|
screen.area, sub_area,
|
||||||
x, y, plot_text = ann
|
Signal(rel_plotarea), Signal(sp)
|
||||||
txt_args = Dict{Symbol, Any}(:model => eye(GeometryTypes.Mat4f0))
|
)
|
||||||
x, y, _1, _1 = Reactive.value(model_m) * Vec{4,Float32}(x, y, 0, 1)
|
|
||||||
extract_font(plot_text.font, txt_args)
|
|
||||||
t = text(Point2f0(x, y), plot_text, txt_args)
|
|
||||||
GLVisualize._view(t, sp_screen, camera=:perspective)
|
|
||||||
end
|
|
||||||
# loop over the series and add them to the subplot
|
# loop over the series and add them to the subplot
|
||||||
if !_3d
|
if !_3d
|
||||||
axis = gl_draw_axes_2d(sp, model_m, Reactive.value(sub_area))
|
axis = gl_draw_axes_2d(sp, model_m, Reactive.value(sub_area))
|
||||||
@ -977,7 +1076,7 @@ function _display(plt::Plot{GLVisualizeBackend}, visible = true)
|
|||||||
if !_3d # 3D is treated differently, since we need boundingboxes for camera
|
if !_3d # 3D is treated differently, since we need boundingboxes for camera
|
||||||
kw_args[:boundingbox] = nothing # don't calculate bb, we dont need it
|
kw_args[:boundingbox] = nothing # don't calculate bb, we dont need it
|
||||||
end
|
end
|
||||||
|
scale_for_annotations!(series)
|
||||||
if st in (:surface, :wireframe)
|
if st in (:surface, :wireframe)
|
||||||
x, y, z = extract_surface(d)
|
x, y, z = extract_surface(d)
|
||||||
extract_gradient(d, kw_args, :fill)
|
extract_gradient(d, kw_args, :fill)
|
||||||
@ -1006,7 +1105,7 @@ function _display(plt::Plot{GLVisualizeBackend}, visible = true)
|
|||||||
if d[:fillrange] != nothing
|
if d[:fillrange] != nothing
|
||||||
kw = copy(kw_args)
|
kw = copy(kw_args)
|
||||||
fr = d[:fillrange]
|
fr = d[:fillrange]
|
||||||
ps = if all(x->x>=0, diff(d[:x])) # if is monotonic
|
ps = if all(x-> x >= 0, diff(d[:x])) # if is monotonic
|
||||||
vcat(points, Point2f0[(points[i][1], cycle(fr, i)) for i=length(points):-1:1])
|
vcat(points, Point2f0[(points[i][1], cycle(fr, i)) for i=length(points):-1:1])
|
||||||
else
|
else
|
||||||
points
|
points
|
||||||
@ -1058,6 +1157,7 @@ function _display(plt::Plot{GLVisualizeBackend}, visible = true)
|
|||||||
else
|
else
|
||||||
error("failed to display plot type $st")
|
error("failed to display plot type $st")
|
||||||
end
|
end
|
||||||
|
|
||||||
isa(vis, Array) && isempty(vis) && continue # nothing to see here
|
isa(vis, Array) && isempty(vis) && continue # nothing to see here
|
||||||
|
|
||||||
GLVisualize._view(vis, sp_screen, camera=:perspective)
|
GLVisualize._view(vis, sp_screen, camera=:perspective)
|
||||||
@ -1068,19 +1168,28 @@ function _display(plt::Plot{GLVisualizeBackend}, visible = true)
|
|||||||
del_signal = Main.GLPlot.register_plot!(vis, sp_screen, create_gizmo=false)
|
del_signal = Main.GLPlot.register_plot!(vis, sp_screen, create_gizmo=false)
|
||||||
append!(_glplot_deletes, del_signal)
|
append!(_glplot_deletes, del_signal)
|
||||||
end
|
end
|
||||||
|
anns = series[:series_annotations]
|
||||||
|
for (x, y, str, font) in EachAnn(anns, d[:x], d[:y])
|
||||||
|
txt_args = Dict{Symbol, Any}(:model => eye(GLAbstraction.Mat4f0))
|
||||||
|
x, y = Reactive.value(model_m) * Vec{4, Float32}(x, y, 0, 1)
|
||||||
|
extract_font(font, txt_args)
|
||||||
|
t = text(Point2f0(x, y), PlotText(str, font), txt_args)
|
||||||
|
GLVisualize._view(t, sp_screen, camera = :perspective)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
generate_legend(sp, sp_screen, model_m)
|
generate_legend(sp, sp_screen, model_m)
|
||||||
if _3d
|
if _3d
|
||||||
GLAbstraction.center!(sp_screen)
|
GLAbstraction.center!(sp_screen)
|
||||||
end
|
end
|
||||||
|
Reactive.post_empty()
|
||||||
|
yield()
|
||||||
end
|
end
|
||||||
Reactive.post_empty()
|
|
||||||
yield()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function _show(io::IO, ::MIME"image/png", plt::Plot{GLVisualizeBackend})
|
function _show(io::IO, ::MIME"image/png", plt::Plot{GLVisualizeBackend})
|
||||||
_display(plt, false)
|
_display(plt, false)
|
||||||
GLWindow.pollevents()
|
GLWindow.poll_glfw()
|
||||||
if Base.n_avail(Reactive._messages) > 0
|
if Base.n_avail(Reactive._messages) > 0
|
||||||
Reactive.run_till_now()
|
Reactive.run_till_now()
|
||||||
end
|
end
|
||||||
@ -1150,14 +1259,7 @@ function gl_shape(d, kw_args)
|
|||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
tovec2(x::FixedSizeArrays.Vec{2, Float32}) = x
|
|
||||||
tovec2(x::AbstractVector) = map(tovec2, x)
|
|
||||||
tovec2(x::FixedSizeArrays.Vec) = Vec2f0(x[1], x[2])
|
|
||||||
|
|
||||||
tovec3(x) = x
|
|
||||||
tovec3(x::FixedSizeArrays.Vec{3}) = Vec3f0(x)
|
|
||||||
tovec3(x::AbstractVector) = map(tovec3, x)
|
|
||||||
tovec3(x::FixedSizeArrays.Vec{2}) = Vec3f0(x[1], x[2], 1)
|
|
||||||
|
|
||||||
function gl_scatter(points, kw_args)
|
function gl_scatter(points, kw_args)
|
||||||
prim = get(kw_args, :primitive, GeometryTypes.Circle)
|
prim = get(kw_args, :primitive, GeometryTypes.Circle)
|
||||||
@ -1167,21 +1269,31 @@ function gl_scatter(points, kw_args)
|
|||||||
kw_args[:scale] = GLAbstraction.const_lift(kw_args[:model], kw_args[:scale], p) do m, sc, p
|
kw_args[:scale] = GLAbstraction.const_lift(kw_args[:model], kw_args[:scale], p) do m, sc, p
|
||||||
s = Vec3f0(m[1,1], m[2,2], m[3,3])
|
s = Vec3f0(m[1,1], m[2,2], m[3,3])
|
||||||
ps = Vec3f0(p[1,1], p[2,2], p[3,3])
|
ps = Vec3f0(p[1,1], p[2,2], p[3,3])
|
||||||
r = sc./(s.*ps)
|
r = sc ./ (s .* ps)
|
||||||
r
|
r
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else # 2D prim
|
else # 2D prim
|
||||||
kw_args[:scale] = tovec2(kw_args[:scale])
|
kw_args[:scale] = to_vec(Vec2f0, kw_args[:scale])
|
||||||
end
|
end
|
||||||
|
|
||||||
if haskey(kw_args, :stroke_width)
|
if haskey(kw_args, :stroke_width)
|
||||||
s = Reactive.value(kw_args[:scale])
|
s = Reactive.value(kw_args[:scale])
|
||||||
sw = kw_args[:stroke_width]
|
sw = kw_args[:stroke_width]
|
||||||
if sw*5 > cycle(Reactive.value(s), 1)[1] # restrict marker stroke to 1/10th of scale (and handle arrays of scales)
|
if sw*5 > cycle(Reactive.value(s), 1)[1] # restrict marker stroke to 1/10th of scale (and handle arrays of scales)
|
||||||
kw_args[:stroke_width] = s[1]/5f0
|
kw_args[:stroke_width] = s[1] / 5f0
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
kw_args[:scale_primitive] = false
|
kw_args[:scale_primitive] = false
|
||||||
|
if isa(prim, String)
|
||||||
|
kw_args[:position] = points
|
||||||
|
if !isa(kw_args[:scale], Vector) # if not vector, we can assume it's relative scale
|
||||||
|
kw_args[:relative_scale] = kw_args[:scale]
|
||||||
|
delete!(kw_args, :scale)
|
||||||
|
end
|
||||||
|
return visualize(prim, Style(:default), kw_args)
|
||||||
|
end
|
||||||
|
|
||||||
visualize((prim, points), Style(:default), kw_args)
|
visualize((prim, points), Style(:default), kw_args)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1201,6 +1313,9 @@ function gl_poly(points, kw_args)
|
|||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function gl_surface(x,y,z, kw_args)
|
function gl_surface(x,y,z, kw_args)
|
||||||
if isa(x, Range) && isa(y, Range)
|
if isa(x, Range) && isa(y, Range)
|
||||||
main = z
|
main = z
|
||||||
@ -1209,8 +1324,8 @@ function gl_surface(x,y,z, kw_args)
|
|||||||
if isa(x, AbstractMatrix) && isa(y, AbstractMatrix)
|
if isa(x, AbstractMatrix) && isa(y, AbstractMatrix)
|
||||||
main = map(s->map(Float32, s), (x, y, z))
|
main = map(s->map(Float32, s), (x, y, z))
|
||||||
elseif isa(x, AbstractVector) || isa(y, AbstractVector)
|
elseif isa(x, AbstractVector) || isa(y, AbstractVector)
|
||||||
x = Float32[x[i] for i=1:size(z,1), j=1:size(z,2)]
|
x = Float32[x[i] for i = 1:size(z,1), j = 1:size(z,2)]
|
||||||
y = Float32[y[j] for i=1:size(z,1), j=1:size(z,2)]
|
y = Float32[y[j] for i = 1:size(z,1), j = 1:size(z,2)]
|
||||||
main = (x, y, map(Float32, z))
|
main = (x, y, map(Float32, z))
|
||||||
else
|
else
|
||||||
error("surface: combination of types not supported: $(typeof(x)) $(typeof(y)) $(typeof(z))")
|
error("surface: combination of types not supported: $(typeof(x)) $(typeof(y)) $(typeof(z))")
|
||||||
@ -1220,8 +1335,10 @@ function gl_surface(x,y,z, kw_args)
|
|||||||
faces = Cuint[]
|
faces = Cuint[]
|
||||||
idx = (i,j) -> sub2ind(size(z), i, j) - 1
|
idx = (i,j) -> sub2ind(size(z), i, j) - 1
|
||||||
for i=1:size(z,1), j=1:size(z,2)
|
for i=1:size(z,1), j=1:size(z,2)
|
||||||
|
|
||||||
i < size(z,1) && push!(faces, idx(i, j), idx(i+1, j))
|
i < size(z,1) && push!(faces, idx(i, j), idx(i+1, j))
|
||||||
j < size(z,2) && push!(faces, idx(i, j), idx(i, j+1))
|
j < size(z,2) && push!(faces, idx(i, j), idx(i, j+1))
|
||||||
|
|
||||||
end
|
end
|
||||||
color = get(kw_args, :stroke_color, RGBA{Float32}(0,0,0,1))
|
color = get(kw_args, :stroke_color, RGBA{Float32}(0,0,0,1))
|
||||||
kw_args[:color] = color
|
kw_args[:color] = color
|
||||||
@ -1237,15 +1354,18 @@ function gl_surface(x,y,z, kw_args)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function gl_contour(x,y,z, kw_args)
|
function gl_contour(x, y, z, kw_args)
|
||||||
if kw_args[:fillrange] != nothing
|
if kw_args[:fillrange] != nothing
|
||||||
|
|
||||||
delete!(kw_args, :intensity)
|
delete!(kw_args, :intensity)
|
||||||
I = GLVisualize.Intensity{1, Float32}
|
I = GLVisualize.Intensity{1, Float32}
|
||||||
main = I[z[j,i] for i=1:size(z, 2), j=1:size(z, 1)]
|
main = I[z[j,i] for i=1:size(z, 2), j=1:size(z, 1)]
|
||||||
return visualize(main, Style(:default), kw_args)
|
return visualize(main, Style(:default), kw_args)
|
||||||
|
|
||||||
else
|
else
|
||||||
h = kw_args[:levels]
|
h = kw_args[:levels]
|
||||||
levels = Contour.contours(x, y, z, h)
|
T = eltype(z)
|
||||||
|
levels = Contour.contours(map(T, x), map(T, y), z, h)
|
||||||
result = Point2f0[]
|
result = Point2f0[]
|
||||||
zmin, zmax = get(kw_args, :limits, Vec2f0(extrema(z)))
|
zmin, zmax = get(kw_args, :limits, Vec2f0(extrema(z)))
|
||||||
cmap = get(kw_args, :color_map, get(kw_args, :color, RGBA{Float32}(0,0,0,1)))
|
cmap = get(kw_args, :color_map, get(kw_args, :color, RGBA{Float32}(0,0,0,1)))
|
||||||
@ -1255,7 +1375,7 @@ function gl_contour(x,y,z, kw_args)
|
|||||||
append!(result, elem.vertices)
|
append!(result, elem.vertices)
|
||||||
push!(result, Point2f0(NaN32))
|
push!(result, Point2f0(NaN32))
|
||||||
col = GLVisualize.color_lookup(cmap, c.level, zmin, zmax)
|
col = GLVisualize.color_lookup(cmap, c.level, zmin, zmax)
|
||||||
append!(colors, fill(col, length(elem.vertices)+1))
|
append!(colors, fill(col, length(elem.vertices) + 1))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
kw_args[:color] = colors
|
kw_args[:color] = colors
|
||||||
@ -1306,9 +1426,12 @@ function label_scatter(d, w, ho)
|
|||||||
if isa(p, GLNormalMesh)
|
if isa(p, GLNormalMesh)
|
||||||
bb = GeometryTypes.AABB{Float32}(GeometryTypes.vertices(p))
|
bb = GeometryTypes.AABB{Float32}(GeometryTypes.vertices(p))
|
||||||
bbw = GeometryTypes.widths(bb)
|
bbw = GeometryTypes.widths(bb)
|
||||||
|
if isapprox(bbw[3], 0)
|
||||||
|
bbw = Vec3f0(bbw[1], bbw[2], 1)
|
||||||
|
end
|
||||||
mini = minimum(bb)
|
mini = minimum(bb)
|
||||||
m = GLAbstraction.translationmatrix(-mini)
|
m = GLAbstraction.translationmatrix(-mini)
|
||||||
m *= GLAbstraction.scalematrix(1f0./bbw)
|
m *= GLAbstraction.scalematrix(1 ./ bbw)
|
||||||
kw[:primitive] = m * p
|
kw[:primitive] = m * p
|
||||||
kw[:scale] = Vec3f0(w/2)
|
kw[:scale] = Vec3f0(w/2)
|
||||||
delete!(kw, :offset)
|
delete!(kw, :offset)
|
||||||
@ -1328,7 +1451,6 @@ function make_label(sp, series, i)
|
|||||||
points = Point2f0[(0, ho), (w, ho)]
|
points = Point2f0[(0, ho), (w, ho)]
|
||||||
kw = KW()
|
kw = KW()
|
||||||
extract_linestyle(d, kw)
|
extract_linestyle(d, kw)
|
||||||
kw[:thickness] = 15f0
|
|
||||||
append!(result, GL.gl_lines(points, kw))
|
append!(result, GL.gl_lines(points, kw))
|
||||||
if d[:markershape] != :none
|
if d[:markershape] != :none
|
||||||
push!(result, label_scatter(d, w, ho))
|
push!(result, label_scatter(d, w, ho))
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user