CalculusWithJuliaNotes.jl/CwJ/makie-demos/inscribed-area.jl

129 lines
3.1 KiB
Julia
Raw Normal View History

2022-05-24 19:51:49 +02:00
using AbstractPlotting
using AbstractPlotting.MakieLayout
using GLMakie
using Roots
## Assumes f(a), f(b) are zero
## only 1 or 2 solutions for f(x) = f(c) for any c in [a,b]
f(x) = 1 - x^4
a = -1
b = 1
descr = """
Adjust the point (c, f(c)) with c > 0 to find the inscribed rectangle with maximal area
"""
function _inscribed_area(c)
zs = fzeros(u -> f(u) - f(c), a, b)
length(zs) <= 1 ? 0 : abs(zs[1] - zs[2]) * f(c)
end
D(f) = c -> (f(c + 1e-4) - f(c))/1e-4
function answer()
h = 1e-4
zs = fzeros(D(_inscribed_area), 0, b-h)
a,i = findmax(_inscribed_area.(zs))
a
end
Answer = answer()
## 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[])
if idx[] == 3
pos = to_world(scene, Point2f0(scene.events.mouseposition[]))
# we work with components not vector
x,y = pos
c = clamp(x, a, b)
zs = fzeros(u -> f(u) - f(c), a , b)
if length(zs) == 1
c = c = first(zs)
else
c, c = zs
end
points[][1] = [c, 0]
points[][2] = [c, f(c)]
points[][3] = [c, f(c)]
points[][4] = [c, 0]
points[] = points[]
end
end
else
dragstart[] = false
end
return
end
end
c = b/2
c = first(fzeros(u -> f(u) - f(c), a , b))
area = round(abs(c - c) * f(c), digits=4)
points = Node(Point2f0[(c,0), (c, f(c)), (c, f(c)), (c, 0)])
# where we lay our scene:
scene, layout = layoutscene()
layout.halign = :left
layout.valign = :top
p = layout[0,0] = LScene(scene)
colsize!(layout, 1, Auto(1))
rowsize!(layout, 1, Auto(1))
label = layout[end, 1] = LText(scene, "Area = $area")
layout[end+1,1] = LText(scene, chomp(descr))
polycolor = lift(points) do pts
c = pts[1][1]
c = pts[3][1]
area = round(abs(c - c)*f(c), digits=4)
lbl = "Area = $area"
label.text[] = lbl
if abs(area - Answer) <= 1e-4
:green
else
:gray75
end
end
lines!(p.scene, a..b, f, strokecolor=:red, strokewidth=15)
lines!(p.scene, a..b, zero, strokecolor=:black, strokewidth=10)
poly!(p.scene, points, color = polycolor)
scatter!(p.scene, points, color = :white, strokewidth = 10, markersize = 0.05, strokecolor = :black, raw = true)
xlims!(p.scene, (a, b))
add_move!(p.scene, points, p.scene[end])
scene