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
|