129 lines
3.1 KiB
Julia
129 lines
3.1 KiB
Julia
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
|