Skip to content

Instantly share code, notes, and snippets.

@ffreyer
Last active February 25, 2023 21:38
Show Gist options
  • Save ffreyer/4008c0aec6bd5b62884e9bdab545e939 to your computer and use it in GitHub Desktop.
Save ffreyer/4008c0aec6bd5b62884e9bdab545e939 to your computer and use it in GitHub Desktop.
Debug Examples
GLMakie.closeall()
scene = Scene()
xs = Observable([0.8, -0.8, -0.8, -0.4, 0.8, 0.1, NaN, 0.0, -0.6])
ys = Observable([0.9, 0.9, 0.1, 0.3, 0.1, 0.7, NaN, 0.7, 0.5])
lines!(scene, xs, ys, linestyle = nothing, linewidth = 20, color = :orange)
lines!(scene, xs, ys, linestyle = :dot, linewidth = 20)
lines!(scene, xs, map(y -> y .- 0.9, ys), linestyle = nothing, linewidth = 20, color = :orange)
lines!(scene, xs, map(y -> y .- 0.9, ys), linestyle = :dash, linewidth = 20)
# scatter!(scene, xs, map(y -> y .- 0.9, ys), color = :red)
screen = display(scene)
# Makie.record(scene, "prototype.mp4", vcat(0:120, 119:-1:1), fps = 30) do i
# xs[][1] = 0.8 - i/200
# notify(ys)
# end
robj = screen.renderlist[1][3]
GLMakie.closeall()
scene = Scene(resolution = (600, 600))
ps = [0.8 * Point2f(cos(x), sin(x)) for x in range(0, pi, length=21)]
push!(ps,
Point2f(-0.3, 0),
Point2f(-0.3, 0.4),
Point2f(-0.05, 0.4),
Point2f(0.0, 0.0),
Point2f(0.05, 0.4),
Point2f(0.3, 0.4),
Point2f(0.3, 0.0),
Point2f(0.8, 0.0)
)
p = lines!(
scene,
ps,
linestyle = :dash,
linewidth = 25,
color = (:black, 1.0)
)
s = scatterlines!(scene, p.converted[1], color = :blue, markersize = 10)
screen = display(scene)
robj = screen.renderlist[1][3]
fig = Figure()
ax = Axis(fig[1, 1], aspect = DataAspect())
xlims!(ax, -3, 6)
ylims!(ax, -4, 2)
# line points
ls = Observable(Point2f[(-2, -2), (0, 0), (5, -3)])
lw = Observable(50)
# constants
AA_THICKNESS = 4
MITER_LIMIT = -0.4
# Semi constants
pattern = GLMakie.ticks([0, 50, 150], 100)
pattern_length = 150
line_data = map(ls, lw, ax.scene.camera.projectionview, ax.scene.camera.resolution
) do ps, lw, pv, res
lw = 0.5lw
screen_pos = map(ps) do p
p4 = to_ndim(Point4f, to_ndim(Point3f, p, 0), 1)
p4_clip = pv * p4
return Point2f(0.5 .* res .* (1 .+ p4_clip[Vec(1,2)]) / p4_clip[4])
end
lastlen = GLMakie.sumlengths(screen_pos)
indices = [1, eachindex(screen_pos)..., length(screen_pos)]
# Triangle definitions
v_pos = Point2f[]
v_idx = Vec3{Int}[]
v_uv = Point2f[]
# Metadata
line_vecs = Vec2f[]
normals = Vec2f[]
miter_vecs = Vec2f[]
miter_lengths = Float32[]
# geom shader
for i in 2:length(indices)-2
# match 0, 1, 2, 3 in shader
i0, i1, i2, i3 = idx_range = indices[i-1:i+2]
# simplified to not include NaN
isvalid = [i0 != i1, true, true, i2 != i3]
# can skip NaN skip
p0, p1, p2, p3 = screen_pos[idx_range]
# don't consider per vertex linewidth
thickness_aa2 = thickness_aa1 = lw + AA_THICKNESS
v0 = (p0 != p1 && isvalid[1]) ? normalize(p1 - p0) : normalize(p2 - p1)
v1 = normalize(p2 - p1)
v2 = (p2 != p3 && isvalid[4]) ? normalize(p3 - p2) : normalize(p2 - p1)
push!(line_vecs, v1)
n0 = Vec2f(-v0[2], v0[1])
n1 = Vec2f(-v1[2], v1[1])
n2 = Vec2f(-v2[2], v2[1])
push!(normals, n1)
miter_a = normalize(n0 + n1)
miter_b = normalize(n1 + n2)
push!(miter_vecs, miter_a)
length_a = thickness_aa1 / dot(miter_a, n1)
length_b = thickness_aa2 / dot(miter_b, n1)
push!(miter_lengths, length_a)
# insert triangle
if dot(v0, v1) < MITER_LIMIT
@info "MITER"
N = length(v_pos)+1
if dot(v0, n1) > 0
push!(v_pos, p1 + thickness_aa1 * n0, p1 + thickness_aa1 * n1, p1)
push!(v_uv,
Point2(lastlen[i1] * 0.5 / pattern_length, -thickness_aa1),
Point2(lastlen[i1] * 0.5 / pattern_length, -thickness_aa1),
Point2(lastlen[i1] * 0.5 / pattern_length, 0.0)
)
push!(v_idx, Vec3(N, N+1, N+2))
else
push!(v_pos, p1 - thickness_aa1 * n0, p1, p1 - thickness_aa1 * n1)
push!(v_uv,
Point2(lastlen[i1] * 0.5 / pattern_length, thickness_aa1),
Point2(lastlen[i1] * 0.5 / pattern_length, 0.0),
Point2(lastlen[i1] * 0.5 / pattern_length, thickness_aa1),
)
push!(v_idx, Vec3(N, N+1, N+2))
end
miter_a = n1
length_a = thickness_aa1
else
nothing
end
if dot(v1, v2) < MITER_LIMIT
miter_b = n1
length_b = thickness_aa2
else
nothing
end
N = length(v_pos)+1
push!(v_pos,
p1 + length_a * miter_a, p1 - length_a * miter_a,
p2 + length_b * miter_b, p2 - length_b * miter_b
)
push!(v_uv,
Point2((lastlen[i1] + length_a * dot(miter_a, v1)) * 0.5 / pattern_length, -thickness_aa1),
Point2((lastlen[i1] - length_a * dot(miter_a, v1)) * 0.5 / pattern_length, thickness_aa1),
Point2((lastlen[i2] + length_b * dot(miter_b, v1)) * 0.5 / pattern_length, -thickness_aa2),
Point2((lastlen[i2] - length_b * dot(miter_b, v1)) * 0.5 / pattern_length, thickness_aa2),
)
push!(v_idx, Vec3(N, N+1, N+2), Vec3(N+1, N+2, N+3))
end
# Let's just dump information
return (
v_pos, v_idx, v_uv,
screen_pos, line_vecs, normals, miter_vecs, miter_lengths,
(0.5 / pattern_length) .* lastlen
)
end
# draw actual lines
lines!(ax, ls, linewidth = 50, linestyle = :dot, linecap = nothing)
# visualize expanded line
_mesh = map(line_data) do (v_pos, v_idx, v_uv, _, _, _, _)
GeometryBasics.Mesh(meta(v_pos), GLTriangleFace.(v_idx))
end
mesh!(ax, _mesh, color = (:lightblue, 0.3), space = :pixel, shading = false, fxaa = false)
wireframe!(ax, _mesh, color = :black, space = :pixel)
# # line vectors and normals
# line_vecs = map(line_data, lw) do data, lw
# origins = getindex(data, 4)
# vecs = lw * getindex(data, 5)
# ps = [origins[div(1+i, 2)] for i in 1:2length(vecs)]
# ps[2:2:end] .+= vecs
# ps
# end
# line_normals = map(line_data, lw) do data, lw
# origins = getindex(data, 4)
# vecs = lw * getindex(data, 6)
# ps = [origins[div(1+i, 2)] for i in 1:2length(vecs)]
# ps[2:2:end] .+= vecs
# ps
# end
# linesegments!(ax, line_vecs, color = :blue, space = :pixel, linewidth=5)
# linesegments!(ax, line_normals, color = :blue, space = :pixel, linewidth=5)
# # miter and length
# miter = map(line_data) do data
# origins = getindex(data, 4)
# miters = getindex(data, 7) .* getindex(data, 8)
# ps = [origins[div(1+i, 2)] for i in 1:2length(miters)]
# ps[2:2:end] .+= miters
# ps
# end
# linesegments!(ax, miter, color = :green, space = :pixel, linewidth=5)
# Visualize dot positions
ps = map(line_data) do data
origins = getindex(data, 4)
vecs = getindex(data, 5)
us = getindex(data, 9)
ps = Point2f[]
target = 0.5 * 25 / 150
for i in 1:length(us)-1
for u in 0:0.5:ceil(us[i+1] - us[i] + (us[i] % 0.5))
push!(ps, origins[i] + (target + u - (us[i] % 0.5)) * 300 * vecs[i])
end
end
ps
end
scatter!(
ax, ps, color = :orange, marker = Circle, markersize = 5,
strokewidth = 2, strokecolor = :black, space = :pixel
)
scatter!(
ax, ps, color = :transparent, marker = Circle, markersize = 50,
strokewidth = 2, strokecolor = :black, space = :pixel
)
# # Visualize us
# ps_us = map(line_data) do data
# origins = getindex(data, 4)
# vecs = getindex(data, 5)
# us = getindex(data, 9)
# segments = Point2f[]
# final_us = Float32[]
# for i in 1:length(us)-1
# push!(segments, origins[i])
# push!(final_us, us[i] % 1.0)
# for u in 0:0.5:ceil(us[i+1] - us[i] + (us[i] % 0.5))
# push!(segments, origins[i] + (u - (us[i] % 0.5)) * 300 * vecs[i])
# push!(segments, origins[i] + (u - (us[i] % 0.5)) * 300 * vecs[i])
# push!(final_us, 1.0, 0.0)
# end
# pop!(segments)
# pop!(final_us)
# end
# segments, final_us
# end
# linesegments!(
# ax, map(first, ps_us), color = map(last, ps_us), colorrange = (0, 1),
# colormap = [:black, :red], linewidth = 10, space = :pixel
# )
# # center line
# lines!(ax, ls, color = :red)
# raw data
plt = scatter!(
ax, ls, color = :white, strokecolor = :green, strokewidth = 2,
overdraw = true
)
selected = Ref(-1)
on(events(fig).mousebutton, priority = 1000) do event
if event.button == Mouse.left
if event.action == Mouse.press
p, idx = pick(fig, mouseposition_px(fig))
if p == plt
selected[] = idx
return Consume(true)
end
elseif event.action == Mouse.release
selected[] = -1
end
end
return Consume(false)
end
on(events(fig).mouseposition, priority = 1000) do _
if selected[] != -1
mpos = mouseposition(ax)
ls[][selected[]] = mpos
notify(ls)
return Consume(true)
end
return Consume(false)
end
fig
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment