{ "cells": [ { "cell_type": "markdown", "id": "c4ad7169", "metadata": {}, "source": [ "##
Julia lang definition of plain-knit yarns
" ] }, { "cell_type": "markdown", "id": "fa1a21b0", "metadata": {}, "source": [ "Recently, K Crane defined 3d curves to model yarns and fibers for simple knitting.\n", "\n", "We reproduce the plots from K Crane's paper, [https://www.cs.cmu.edu/~kmcrane/Projects/Other/YarnCurve.pdf](https://www.cs.cmu.edu/~kmcrane/Projects/Other/YarnCurve.pdf),\n", "taking the advantage of Julia, over C programming language,\n", "to write a more compact code, and moreover to plot the graphical objects directly, \n", "without involving an external library. Notice that automatic derivation (via ForwardDiff.jl) of vector valued functions $t\\mapsto γ(t)$, $t\\mapsto\\dot{γ}(t)$, substantially reduces the lines of code, compared to the C version." ] }, { "cell_type": "markdown", "id": "ffdc2e06", "metadata": {}, "source": [ "The yarns are represented as tubular surfaces, having as directrice a 3d curve, $t\\to\\gamma(t)\\in\\mathbb{R}^3$. To get the tube parameterizaion we implement the A. Hanson's algorithm, presented in *Visualizing Quaternions*, Morgan Kaufmann, 2006:\n" ] }, { "cell_type": "code", "execution_count": null, "id": "447f71f8", "metadata": {}, "outputs": [], "source": [ "import ForwardDiff.derivative\n", "import LinearAlgebra: norm, cross\n", "import Rotations.UnitQuaternion\n", "using PlotlyJS " ] }, { "cell_type": "code", "execution_count": null, "id": "99ac8b3c", "metadata": {}, "outputs": [], "source": [ "dγ(t)=derivative(γ, t) # t->̇γ(t)\n", "ddγ(t)=derivative(dγ, t) #t->̈γ(t)\n", "\n", "#get the tubular surface parameterization:\n", "function tube(γ::T, u::S, v::S; radius=0.1) where {S<:Real, T<:Function}\n", " tang = dγ(u) #tangent(γ, u)\n", " ~iszero(tang) || error(\"null tangent vector!\")\n", " unittan = tang/norm(tang)\n", " θ = acos(unittan[1])/2\n", " crossp= [0, -unittan[3], unittan[2]] # cross product [1,0,0] x unittan\n", " quvect = sin(θ)*crossp/norm(crossp) #3-vector to define the quaternion \n", " #q=(cos(θ), sin(θ)*unitvect)\n", " q = isapprox(θ, π/2) ? UnitQuaternion(0, 0, 1, 0) : isapprox(θ, 0) ? \n", " UnitQuaternion(1, 0 , 0, 0) : UnitQuaternion(cos(θ), quvect...)\n", " _, n₁, n₂, = eachcol(q)\n", " return γ(u) + radius*cos(v) * n₁ + radius*sin(v) * n₂\n", "end \n", "\n", "#define a fiber curve parameterization (§3.2 Fiber Curves in K Crane's paper)\n", "function fiber_curve(γ::T₁; \n", " ω=4, r=0.5, Φ=0) where {T₁} #, T₂, T₃<:Function\n", " # curve is t->γ(t), dγ: t->̇γ(t), ddγ: t->̈γ(t)\n", " θ(t) = ω*t −2cos(t)+Φ\n", " unittan(t) = dγ(t)/norm(dγ(t))\n", " unitacc(t) = ddγ(t)/norm(ddγ(t))\n", " n₂(t) = cross(unittan(t), unitacc(t)) #binormal\n", " n₁(t) = cross(n₂(t), unittan(t)) #principal normal\n", " t->γ(t) + r*cos(θ(t)) * n₁(t) + r*sin(θ(t)) * n₂(t)\n", "end " ] }, { "cell_type": "markdown", "id": "a31165ef", "metadata": {}, "source": [ "Define the PlotlyJS type data for plotting yarns and fibers:" ] }, { "cell_type": "code", "execution_count": null, "id": "e8840b00", "metadata": {}, "outputs": [], "source": [ "burgundy = [[0, \"#e26152\"], [1, \"#e26152\"]] #kind of burgundy color\n", "silver = [[0, \"#bebebe\"], [1.0, \"#bebebe\"]] #silver color\n", "\n", "function surf(x::Matrix{T} , y::Matrix{T}, z::Matrix{T}; colorscale=burgundy) where T<:Real\n", " surface(x=x, y=y, z=z, hoverinfo=\"skip\",\n", " colorscale=colorscale, \n", " showscale=false,\n", " lighting=attr(ambient=0.45,\n", " diffuse=0.35,\n", " fresnel=0.5, \n", " specular=0.25,\n", " roughness=0.45),\n", " lightposition=attr(x=100,\n", " y=100,\n", " z=100 \n", " )) \n", "end\n", "\n", "axes_off(fig)=\n", " relayout!(fig, scene =attr(xaxis_visible=false, \n", " yaxis_visible=false,\n", " zaxis_visible=false))\n", "\n", "function plot_data(traces) \n", " fig = Plot(traces, \n", " Layout(width=450, height=450, \n", " #margin=attr(t=2, r=2, b=2, l=2),\n", " scene=attr(aspectmode=\"data\", \n", " camera_eye=attr(x=2.7, y=0, z=0.5))\n", " )) \n", " axes_off(fig)\n", " fig\n", "end " ] }, { "cell_type": "markdown", "id": "075b6734", "metadata": {}, "source": [ "### 1. Yarn curves " ] }, { "cell_type": "code", "execution_count": null, "id": "eac06197", "metadata": {}, "outputs": [], "source": [ "#K. Crane's yarn curve rotated π/2 about y-axis, then π/2 about x-axis\n", "γ(t; a=1.5, h=4, d=1) = [d*cos(2t), t+a*sin(2t), h*cos(t)]\n", "u = range(0, 8π, length=600)\n", "v = range(0, 2π, length=100); \n", "\n", "x, y, z = [getindex.(tube.(γ, u, v'; radius=4/5), i) for i∈1:3]\n", "fig1 = plot_data([surf(x, y, z .+ k*4.5) for k in 0:3]) \n" ] }, { "cell_type": "markdown", "id": "a4f57bcf", "metadata": {}, "source": [ "![burgundy](https://raw.githubusercontent.com/empet/Datasets/master/Images/yarncurves1.png)" ] }, { "cell_type": "markdown", "id": "c3343727", "metadata": {}, "source": [ "![silverish](https://raw.githubusercontent.com/empet/Datasets/master/Images/yarncurves3.png)" ] }, { "cell_type": "markdown", "id": "466555fb", "metadata": {}, "source": [ "### 2. Twisted yarn fibers" ] }, { "cell_type": "code", "execution_count": null, "id": "bca238da", "metadata": {}, "outputs": [], "source": [ "γ(t; a=1.5, h=4, d=1)= [d*cos(2t), t+a*sin(2t), h*cos(t)] #curve \n", "fcurves = [fiber_curve(γ; ω= 4, Φ=k*π/2) for k ∈ 0:3];" ] }, { "cell_type": "code", "execution_count": null, "id": "0dd0e8cc", "metadata": { "scrolled": false }, "outputs": [], "source": [ "u = range(0, 8π, length=600)\n", "v = range(0, 2π, length=100); \n", "fibers = GenericTrace{Dict{Symbol, Any}}[]\n", "for fcurve ∈ fcurves\n", " x, y, z = [getindex.(tube.(fcurve, u, v'; radius=7/20), i) for i∈ 1:3]\n", " push!(fibers, surf(x, y, z))\n", "end \n", "fig2 = plot_data(fibers)" ] }, { "cell_type": "markdown", "id": "b5f4cbed", "metadata": {}, "source": [ "Fiber curves for $\\omega=2, 4, 6$:" ] }, { "cell_type": "markdown", "id": "fccff3bd", "metadata": {}, "source": [ "![fibers](https://raw.githubusercontent.com/empet/Datasets/master/Images/fibers.png)" ] }, { "cell_type": "code", "execution_count": null, "id": "4c94109b", "metadata": {}, "outputs": [], "source": [ "fibers = GenericTrace{Dict{Symbol, Any}}[]\n", "for fcurve ∈ fcurves\n", " x, y, z = [getindex.(tube.(fcurve, u, v'; radius=7/20),i) for i∈ 1:3]\n", " append!(fibers, [surf(x, y, z .+ j*4.5) for j∈0:3])#a fiber contains 4 twisted yarns(j=0:3)\n", "end \n", "fig3 = plot_data(fibers)" ] }, { "cell_type": "markdown", "id": "f86d02a4", "metadata": {}, "source": [ "![knitted o4](https://raw.githubusercontent.com/empet/Datasets/master/Images/knittedomega4.webp)" ] }, { "cell_type": "code", "execution_count": null, "id": "5df4ac0b", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "@webio": { "lastCommId": null, "lastKernelId": null }, "kernelspec": { "display_name": "Julia 1.9.0", "language": "julia", "name": "julia-1.9" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", "version": "1.9.0" } }, "nbformat": 4, "nbformat_minor": 5 }