152 lines
3.9 KiB
Julia
152 lines
3.9 KiB
Julia
|
using AbstractPlotting
|
|||
|
using AbstractPlotting.MakieLayout
|
|||
|
using GLMakie
|
|||
|
|
|||
|
using LinearAlgebra
|
|||
|
using Roots
|
|||
|
using ForwardDiff
|
|||
|
D(f) = x -> ForwardDiff.derivative(f, float(x))
|
|||
|
|
|||
|
descr = """
|
|||
|
An old optimization problem is to find the shortest distance between two
|
|||
|
points when the rate of travel differs due to some medium (darker means slower).
|
|||
|
In this example, the relative rate can be adjusted (with the slider), and the
|
|||
|
various points (by clicking on and dragging a point). From there, the
|
|||
|
user can adjust the crossing point to identify the time.
|
|||
|
"""
|
|||
|
|
|||
|
## From http://juliaplots.org/MakieReferenceImages/gallery//edit_polygon/index.html:
|
|||
|
function add_move!(scene, points, pplot)
|
|||
|
idx = Ref(0); dragstart = Ref(false); startpos = Base.RefValue(Point2f0(0))
|
|||
|
on(events(scene).mousedrag) do drag
|
|||
|
if ispressed(scene, Mouse.left)
|
|||
|
if drag == Mouse.down
|
|||
|
plot, _idx = mouse_selection(scene)
|
|||
|
if plot == pplot
|
|||
|
idx[] = _idx; dragstart[] = true
|
|||
|
startpos[] = to_world(scene, Point2f0(scene.events.mouseposition[]))
|
|||
|
end
|
|||
|
elseif drag == Mouse.pressed && dragstart[] && checkbounds(Bool, points[], idx[])
|
|||
|
pos = to_world(scene, Point2f0(scene.events.mouseposition[]))
|
|||
|
|
|||
|
# very wierd, but we work with components
|
|||
|
# not vector
|
|||
|
z = zero(eltype(pos))
|
|||
|
x,y = pos
|
|||
|
|
|||
|
ptidx = idx[]
|
|||
|
|
|||
|
x = clamp(x, 0, 5)
|
|||
|
|
|||
|
if ptidx == 1
|
|||
|
y = clamp(y, z, 5)
|
|||
|
elseif ptidx == 2
|
|||
|
y = z
|
|||
|
elseif ptidx == 3
|
|||
|
y = clamp(y, -5, z)
|
|||
|
end
|
|||
|
|
|||
|
points[][idx[]] = [x,y]
|
|||
|
points[] = points[]
|
|||
|
end
|
|||
|
else
|
|||
|
dragstart[] = false
|
|||
|
end
|
|||
|
return
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
upperpoints = Point2f0[(0,0), (5, 0), (5, 5), (0,5)]
|
|||
|
lowerpoints = (Point2f0[(0,0), (5, 0), (5, -5), (0,-5)])
|
|||
|
|
|||
|
points = Node(Point2f0[(1, 4), (3, 0), (4,-4.0)])
|
|||
|
|
|||
|
# where we lay our scene:
|
|||
|
scene, layout = layoutscene()
|
|||
|
layout.halign = :left
|
|||
|
layout.valign = :top
|
|||
|
|
|||
|
|
|||
|
p = layout[1:3, 1] = LScene(scene)
|
|||
|
rowsize!(layout, 1, Auto(1))
|
|||
|
colsize!(layout, 1, Auto(1))
|
|||
|
|
|||
|
|
|||
|
flayout = GridLayout()
|
|||
|
layout[1,2] = flayout
|
|||
|
|
|||
|
flayout[1,1] = LText(scene, chomp(descr))
|
|||
|
|
|||
|
details = flayout[2, 1] = LText(scene, "...")
|
|||
|
|
|||
|
λᵣ = flayout[3,1] = LText(scene, "λ = v₁/v₂ = 1")
|
|||
|
λ = flayout[4,1] = LSlider(scene, range = -3:0.2:3, startvalue = 0.0)
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
tm = lift(λ.value, points) do λ, pts
|
|||
|
x0,y0 = pts[1]
|
|||
|
x, y = pts[2]
|
|||
|
x1, y1 = pts[3]
|
|||
|
|
|||
|
v1 = 1
|
|||
|
v2 = v1/2.0^λ
|
|||
|
|
|||
|
t(x) = sqrt((x-x0)^2 + y0^2)/v1 + sqrt((x1-x)^2 + y1^2)/v2
|
|||
|
val = t(x)
|
|||
|
|
|||
|
details.text[] = "Time: $(round(val, digits=2)) units"
|
|||
|
|
|||
|
val
|
|||
|
|
|||
|
end
|
|||
|
|
|||
|
a = lift(λ.value, points) do λ, pts
|
|||
|
x0,y0 = pts[1]
|
|||
|
x1, y1 = pts[3]
|
|||
|
v1 = 1
|
|||
|
v2 = v1/2.0^λ
|
|||
|
|
|||
|
t(x) = sqrt((x-x0)^2 + y0^2)/v1 + sqrt((x1-x)^2 + y1^2)/v2
|
|||
|
x′ = fzero(D(t), x0, x1)
|
|||
|
t(x′)
|
|||
|
end
|
|||
|
|
|||
|
λcolor = lift(λ.value) do val
|
|||
|
# val = v1/v2 ∈ [1/8, 8]
|
|||
|
n = floor(Int, 50 - val/3 * 25)
|
|||
|
Symbol("gray" * string(n))
|
|||
|
end
|
|||
|
|
|||
|
linecolor = lift(a) do val
|
|||
|
abs(val - tm[]) <= 1e-2 ? :green : :white
|
|||
|
end
|
|||
|
|
|||
|
|
|||
|
on(λ.value) do val
|
|||
|
v = round(2.0^(val), digits=2)
|
|||
|
txt = "λ = v₁/v₂ = $v"
|
|||
|
λᵣ.text[] = txt
|
|||
|
|
|||
|
|
|||
|
end
|
|||
|
|
|||
|
|
|||
|
|
|||
|
poly!(p.scene, upperpoints, color = :gray50) # neutral color
|
|||
|
poly!(p.scene, lowerpoints, color = λcolor) # color depends on λ
|
|||
|
|
|||
|
lines!(p.scene, Point2f0[(0,0), (5, 0)], color=:black, strokewidth=5, strokecolor=:black, raw=true)
|
|||
|
lines!(p.scene, points, color = linecolor, strokewidth = 10, markersize = 0.05, strokecolor = :black, raw = true)
|
|||
|
scatter!(p.scene, points, color = linecolor, strokewidth = 10, markersize = 0.05, strokecolor = :black, raw = true)
|
|||
|
xlims!(p.scene, (0,5))
|
|||
|
ylims!(p.scene, (-5,5))
|
|||
|
|
|||
|
add_move!(p.scene, points, p.scene[end])
|
|||
|
|
|||
|
|
|||
|
|
|||
|
scene
|
|||
|
|