{
 "cells": [
  {
   "cell_type": "markdown",
   "source": [
    "Weaving a transformable curved surface from catenoid to helicoid.\n",
    "You can buy the kit [via my Booth site](https://hyrodium.booth.pm/items/5046306)!"
   ],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "![](../assets/helicatenoid2.jpg)"
   ],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Load packages"
   ],
   "metadata": {}
  },
  {
   "outputs": [],
   "cell_type": "code",
   "source": [
    "using Luxor\n",
    "using IntervalSets\n",
    "using BasicBSpline\n",
    "using BasicBSplineFitting\n",
    "using StaticArrays\n",
    "using ElasticSurfaceEmbedding\n",
    "using LinearAlgebra"
   ],
   "metadata": {},
   "execution_count": 1
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Define the shape of the surface"
   ],
   "metadata": {}
  },
  {
   "outputs": [
    {
     "output_type": "execute_result",
     "data": {
      "text/plain": "f2 (generic function with 1 method)"
     },
     "metadata": {},
     "execution_count": 2
    }
   ],
   "cell_type": "code",
   "source": [
    "const N = 8\n",
    "const J = 1\n",
    "f0(s) = max(-abs(s+1/2N-1)-(1/2N-1), 0)\n",
    "f1(s) = -1/2+f0(mod(s-J/N, 2))\n",
    "f2(s) = 1/2-f0(mod(s-1-J/N, 2))"
   ],
   "metadata": {},
   "execution_count": 2
  },
  {
   "cell_type": "markdown",
   "source": [
    "0≤u≤2π, -π/2≤v≤π/2\n",
    "0≤s≤2, 0≤t≤1"
   ],
   "metadata": {}
  },
  {
   "outputs": [],
   "cell_type": "code",
   "source": [
    "u(s,t) = π*s\n",
    "v(s,t) = π*(f1(s)*(1-t) + t*f2(s))\n",
    "catenoid(u,v) = SVector(cos(u)*cosh(v),sin(u)*cosh(v),v)\n",
    "ElasticSurfaceEmbedding.𝒑₍₀₎(s,t) = catenoid(u(s,t), v(s,t))"
   ],
   "metadata": {},
   "execution_count": 3
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Compute the shape of the embeddings"
   ],
   "metadata": {}
  },
  {
   "outputs": [],
   "cell_type": "code",
   "source": [
    "splitat = [-1/N, -1/2N, 0, 1/2N, 1/N, 1, 1+1/2N, 1+1/N]\n",
    "steptree = StepTree()\n",
    "for shift in [0, -1/N, -2/N, -3/N]\n",
    "    initial_state!(steptree, (0+shift..2+shift, 0..1), splitat)\n",
    "    newton_onestep!(steptree, fixingmethod=:fix5points)\n",
    "    newton_onestep!(steptree, fixingmethod=:fix3points)\n",
    "    newton_onestep!(steptree)\n",
    "    refinement!(steptree, p₊=(0,1), k₊=ElasticSurfaceEmbedding.suggest_knotvector(steptree))\n",
    "    for _ in 1:5 newton_onestep!(steptree) end\n",
    "    pin!(steptree)\n",
    "end"
   ],
   "metadata": {},
   "execution_count": 4
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Helper functions to export svg images"
   ],
   "metadata": {}
  },
  {
   "outputs": [
    {
     "output_type": "execute_result",
     "data": {
      "text/plain": "svector2point (generic function with 1 method)"
     },
     "metadata": {},
     "execution_count": 5
    }
   ],
   "cell_type": "code",
   "source": [
    "function create_bezierpath(C::BSplineManifold{1,(3,),Point})\n",
    "    P = bsplinespaces(C)[1]\n",
    "    k = knotvector(P)\n",
    "    k′ = 3*unique(k) + k[[1,end]]\n",
    "    P′ = BSplineSpace{3}(k′)\n",
    "    C′ = refinement(C,P′)\n",
    "    a′ = controlpoints(C′)\n",
    "    n′ = dim(P′)\n",
    "    m = (n′-1) ÷ 3\n",
    "    bezierpath = BezierPath([BezierPathSegment(a′[3i-2], a′[3i-1], a′[3i], a′[3i+1]) for i in 1:m])\n",
    "    return bezierpath\n",
    "end\n",
    "function svector2point(M::BSplineManifold)\n",
    "    P = bsplinespaces(M)\n",
    "    a = controlpoints(M)\n",
    "    a′ = [Point(p[1], -p[2])*100/π for p in a]\n",
    "    M′ = BSplineManifold(a′, P)\n",
    "    return M′\n",
    "end"
   ],
   "metadata": {},
   "execution_count": 5
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Settings for export"
   ],
   "metadata": {}
  },
  {
   "outputs": [
    {
     "output_type": "execute_result",
     "data": {
      "text/plain": "400"
     },
     "metadata": {},
     "execution_count": 6
    }
   ],
   "cell_type": "code",
   "source": [
    "xlims=(-2,2)\n",
    "ylims=(-2,2)\n",
    "unitlength = (100, \"mm\")\n",
    "\n",
    "width = (xlims[2] - xlims[1]) * unitlength[1]\n",
    "height = (ylims[2] - ylims[1]) * unitlength[1]"
   ],
   "metadata": {},
   "execution_count": 6
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Export embeddings"
   ],
   "metadata": {}
  },
  {
   "outputs": [],
   "cell_type": "code",
   "source": [
    "mkpath(\"helicatenoid2\")\n",
    "for i in 1:(N+1)÷2\n",
    "    filepath = joinpath(\"helicatenoid2\", \"embedding-$(i).svg\")\n",
    "    M = svector2point(steptree.steps[10i].manifold)\n",
    "    D¹ = domain(bsplinespaces(M)[1])\n",
    "    D² = domain(bsplinespaces(M)[2])\n",
    "    u²₋ = minimum(D²)\n",
    "    u²₊ = maximum(D²)\n",
    "\n",
    "    Drawing(width, height, filepath)\n",
    "    origin()\n",
    "    background(\"white\")\n",
    "    sethue(\"red\")\n",
    "\n",
    "    C = M(:,u²₋)\n",
    "    path = create_bezierpath(C)\n",
    "    drawbezierpath(path, :stroke)\n",
    "    C = M(:,u²₊)\n",
    "    path = create_bezierpath(C)\n",
    "    drawbezierpath(path, :stroke)\n",
    "\n",
    "    p1 = controlpoints(M)[begin,begin]\n",
    "    p2 = controlpoints(M)[begin,end]\n",
    "    p3 = controlpoints(M)[end,begin]\n",
    "    p4 = controlpoints(M)[end,end]\n",
    "\n",
    "    v12 = p1-p2\n",
    "    q1 = p1 - Point(v12[2],-v12[1])/norm(v12) * 6\n",
    "    q2 = p2 - Point(v12[2],-v12[1])/norm(v12) * 6\n",
    "    line(p1,q1)\n",
    "    line(q2)\n",
    "    line(p2)\n",
    "    strokepath()\n",
    "\n",
    "    v34 = p3-p4\n",
    "    q3 = p3 + Point(v34[2],-v34[1])/norm(v34) * 6\n",
    "    q4 = p4 + Point(v34[2],-v34[1])/norm(v34) * 6\n",
    "    line(p3,q3)\n",
    "    line(q4)\n",
    "    line(p4)\n",
    "    strokepath()\n",
    "\n",
    "    finish()\n",
    "    preview()\n",
    "\n",
    "    script = read(filepath, String)\n",
    "    lines = split(script, \"\\n\")\n",
    "    lines[2] = replace(lines[2],\"pt\\\"\"=>\"mm\\\"\")\n",
    "    write(filepath, join(lines,\"\\n\"))\n",
    "end"
   ],
   "metadata": {},
   "execution_count": 7
  },
  {
   "cell_type": "markdown",
   "source": [
    "The output files will be saved as `embedding-$(i).svg`."
   ],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "![](helicatenoid2/embedding-1.svg)\n",
    "![](helicatenoid2/embedding-2.svg)\n",
    "![](helicatenoid2/embedding-3.svg)\n",
    "![](helicatenoid2/embedding-4.svg)"
   ],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "# References\n",
    "- [懸垂面螺旋面製作キット](https://hackmd.io/@hyrodium/Hy4D5r633)"
   ],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "---\n",
    "\n",
    "*This notebook was generated using [Literate.jl](https://github.com/fredrikekre/Literate.jl).*"
   ],
   "metadata": {}
  }
 ],
 "nbformat_minor": 3,
 "metadata": {
  "language_info": {
   "file_extension": ".jl",
   "mimetype": "application/julia",
   "name": "julia",
   "version": "1.11.4"
  },
  "kernelspec": {
   "name": "julia-1.11",
   "display_name": "Julia 1.11.4",
   "language": "julia"
  }
 },
 "nbformat": 4
}