Helicatenoid2

Source code notebook

Weaving a transformable curved surface from catenoid to helicoid.

Load packages

using Luxor
using IntervalSets
using BasicBSpline
using BasicBSplineFitting
using StaticArrays
using ElasticSurfaceEmbedding
using LinearAlgebra

Define the shape of the surface

const N = 8
const J = 1
f0(s) = max(-abs(s+1/2N-1)-(1/2N-1), 0)
f1(s) = -1/2+f0(mod(s-J/N, 2))
f2(s) = 1/2-f0(mod(s-1-J/N, 2))
f2 (generic function with 1 method)

0≤u≤2π, -π/2≤v≤π/2 0≤s≤2, 0≤t≤1

u(s,t) = π*s
v(s,t) = π*(f1(s)*(1-t) + t*f2(s))
catenoid(u,v) = SVector(cos(u)*cosh(v),sin(u)*cosh(v),v)
ElasticSurfaceEmbedding.𝒑₍₀₎(s,t) = catenoid(u(s,t), v(s,t))

Compute the shape of the embeddings

splitat = [-1/N, -1/2N, 0, 1/2N, 1/N, 1, 1+1/2N, 1+1/N]
steptree = StepTree()
for shift in [0, -1/N, -2/N, -3/N]
    initial_state!(steptree, (0+shift..2+shift, 0..1), splitat)
    newton_onestep!(steptree, fixingmethod=:fix5points)
    newton_onestep!(steptree, fixingmethod=:fix3points)
    newton_onestep!(steptree)
    refinement!(steptree, p₊=(0,1), k₊=ElasticSurfaceEmbedding.suggest_knotvector(steptree))
    for _ in 1:5 newton_onestep!(steptree) end
    pin!(steptree)
end

Helper functions to export svg images

function create_bezierpath(C::BSplineManifold{1,(3,),Point})
    P = bsplinespaces(C)[1]
    k = knotvector(P)
    k′ = 3*unique(k) + k[[1,end]]
    P′ = BSplineSpace{3}(k′)
    C′ = refinement(C,P′)
    a′ = controlpoints(C′)
    n′ = dim(P′)
    m = (n′-1) ÷ 3
    bezierpath = BezierPath([BezierPathSegment(a′[3i-2], a′[3i-1], a′[3i], a′[3i+1]) for i in 1:m])
    return bezierpath
end
function svector2point(M::BSplineManifold)
    P = bsplinespaces(M)
    a = controlpoints(M)
    a′ = [Point(p[1], -p[2])*100/π for p in a]
    M′ = BSplineManifold(a′, P)
    return M′
end
svector2point (generic function with 1 method)

Settings for export

xlims=(-2,2)
ylims=(-2,2)
unitlength = (100, "mm")

width = (xlims[2] - xlims[1]) * unitlength[1]
height = (ylims[2] - ylims[1]) * unitlength[1]
400

Export embeddings

mkpath("helicatenoid2")
for i in 1:(N+1)÷2
    filepath = joinpath("helicatenoid2", "embedding-$(i).svg")
    M = svector2point(steptree.steps[10i].manifold)
    D¹ = domain(bsplinespaces(M)[1])
    D² = domain(bsplinespaces(M)[2])
    u²₋ = minimum(D²)
    u²₊ = maximum(D²)

    Drawing(width, height, filepath)
    origin()
    background("white")
    sethue("red")

    C = M(:,u²₋)
    path = create_bezierpath(C)
    drawbezierpath(path, :stroke)
    C = M(:,u²₊)
    path = create_bezierpath(C)
    drawbezierpath(path, :stroke)

    p1 = controlpoints(M)[begin,begin]
    p2 = controlpoints(M)[begin,end]
    p3 = controlpoints(M)[end,begin]
    p4 = controlpoints(M)[end,end]

    v12 = p1-p2
    q1 = p1 - Point(v12[2],-v12[1])/norm(v12) * 6
    q2 = p2 - Point(v12[2],-v12[1])/norm(v12) * 6
    line(p1,q1)
    line(q2)
    line(p2)
    strokepath()

    v34 = p3-p4
    q3 = p3 + Point(v34[2],-v34[1])/norm(v34) * 6
    q4 = p4 + Point(v34[2],-v34[1])/norm(v34) * 6
    line(p3,q3)
    line(q4)
    line(p4)
    strokepath()

    finish()
    preview()

    script = read(filepath, String)
    lines = split(script, "\n")
    lines[2] = replace(lines[2],"pt\""=>"mm\"")
    write(filepath, join(lines,"\n"))
end

The output files will be saved as embedding-$(i).svg.


This page was generated using DemoCards.jl and Literate.jl.