# Drawing a tubular path with Meshes.jl (blog post)

**URL:** <https://discourse.julialang.org/t/drawing-a-tubular-path-with-meshes-jl-blog-post/104203>\
**Category:** Community\
**Tags:** plotting\
**Created:** [September 24, 2023, 11:22pm UTC](https://discourse.julialang.org/t/drawing-a-tubular-path-with-meshes-jl-blog-post/104203 "2023-09-24T23:22:37Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![\_stla](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/_stla/32/35613_2.png) [@\_stla](https://discourse.julialang.org/u/_stla)\
**Post date:** [September 24, 2023, 11:22pm UTC](https://discourse.julialang.org/t/drawing-a-tubular-path-with-meshes-jl-blog-post/104203/1 "2023-09-24T23:22:37Z")

</div>

Hello,

Follow [the link to my blog](https://laustep.github.io/stlahblog/posts/juliaTube.html).

---

<div class="post-metadata">

**Author:** ![empet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/empet/32/221303_2.png) [@empet](https://discourse.julialang.org/u/empet)\
**Post date:** [September 25, 2023, 6:28am UTC](https://discourse.julialang.org/t/drawing-a-tubular-path-with-meshes-jl-blog-post/104203/2 "2023-09-25T06:28:35Z")

</div>

It is much simpler to define a tubular surface of directional curve, γ, using quaternions:

```julia
import ForwardDiff.derivative
import LinearAlgebra: norm, cross
import Rotations.UnitQuaternion

dγ(t)=derivative(γ, t) # t->̇γ(t)
ddγ(t)=derivative(dγ, t) #t->̈γ(t)

#get the tubular surface parameterization:
function tube(γ::T, u::S, v::S; radius=0.1) where {S<:Real, T<:Function}
    tang = dγ(u) #tangent(γ, u)
    ~iszero(tang) || error("null tangent vector!")
    unittan = tang/norm(tang)
    θ = acos(unittan[1])/2
    crossp= [0, -unittan[3], unittan[2]] # cross product [1,0,0] x unittan
    quvect = sin(θ)*crossp/norm(crossp) #3-vector to define the quaternion 
                                          #q=(cos(θ), sin(θ)*unitvect)
    q = isapprox(θ, π/2) ? UnitQuaternion(0, 0, 1, 0) : isapprox(θ, 0) ? 
                   UnitQuaternion(1, 0 , 0, 0) : UnitQuaternion(cos(θ), quvect...)
    _, n₁, n₂, = eachcol(q)
    return γ(u) + radius*cos(v) * n₁ + radius*sin(v) * n₂
end 

```

[Example](https://nbviewer.org/github/empet/Plain-knit-yarns-modeling/blob/main/Plain-Knit-Yarns-modeling.ipynb)

---

<div class="post-metadata">

**Author:** ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)\
**Post date:** [September 25, 2023, 10:09am UTC](https://discourse.julialang.org/t/drawing-a-tubular-path-with-meshes-jl-blog-post/104203/3 "2023-09-25T10:09:29Z")

</div>

Very nice examples. I invite you all to contribute the `Tube` primitive to Meshes.jl:

> <https://github.com/JuliaGeometry/Meshes.jl/issues/349>
>
> Issue to track our efforts adding more primitives.
> 
> \- \[x\] Disk
> \- \[x\] Circle
> …- \[x\] Cone
> \- \[x\] ConeSurface
> \- \[x\] Torus
> \- \[x\] Frustum
> \- \[\] Tube
> \- \[\] Ellipsoid

We had an attempt by @_stla in the past, but it didn’t went through. Happy to review other attempts and parametrizations.

---

<div class="post-metadata">

**Author:** ![\_stla](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/_stla/32/35613_2.png) [@\_stla](https://discourse.julialang.org/u/_stla)\
**Post date:** [September 25, 2023, 4:42pm UTC](https://discourse.julialang.org/t/drawing-a-tubular-path-with-meshes-jl-blog-post/104203/4 "2023-09-25T16:42:33Z")

</div>

@empet With “my” method (it’s not mine), you can choose the number of sides and you can twist the tube.

The conciseness of yours is amazing.

---

<div class="post-metadata">

**Author:** ![\_stla](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/_stla/32/35613_2.png) [@\_stla](https://discourse.julialang.org/u/_stla)\
**Post date:** [September 25, 2023, 4:43pm UTC](https://discourse.julialang.org/t/drawing-a-tubular-path-with-meshes-jl-blog-post/104203/5 "2023-09-25T16:43:55Z")

</div>

Wow I’ve just seen your examples, awesome!

---

<div class="post-metadata">

**Author:** ![empet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/empet/32/221303_2.png) [@empet](https://discourse.julialang.org/u/empet)\
**Post date:** [September 25, 2023, 6:02pm UTC](https://discourse.julialang.org/t/drawing-a-tubular-path-with-meshes-jl-blog-post/104203/6 "2023-09-25T18:02:54Z")

</div>

@_stla It was a kind of challenge to illustrate how short can be the Julia code to generate the same geometric  
object, defined by Krane in C, and by someone elese in Python (see the links in the README file [here](https://github.com/keenancrane/plain-knit-yarn)).  
I discovered the Hanson’s algorithm for more than an year, but I postponed its implementation, and this was an opportunity to do it.  
@juliohm I have also defined the tube triangulation, and I can provide it, but I cannot make a PR, because I have a little experience with git. I can only assist you with the theoretical approach of the surfaces listed above, in the to do list.

---

<div class="post-metadata">

**Author:** ![\_stla](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/_stla/32/35613_2.png) [@\_stla](https://discourse.julialang.org/u/_stla)\
**Post date:** [September 25, 2023, 6:23pm UTC](https://discourse.julialang.org/t/drawing-a-tubular-path-with-meshes-jl-blog-post/104203/7 "2023-09-25T18:23:50Z")

</div>

@empet The main difference between our two implementations is that yours takes as input a function, that you can derivate to get the tangents, the normals and the binormals, whereas mine is for a discrete curve. But it’s true that usually we sample the trajectory of a given function to get a discrete path, so in this case it’s better to use your method.

---

<div class="post-metadata">

**Author:** ![\_stla](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/_stla/32/35613_2.png) [@\_stla](https://discourse.julialang.org/u/_stla)\
**Post date:** [September 25, 2023, 6:29pm UTC](https://discourse.julialang.org/t/drawing-a-tubular-path-with-meshes-jl-blog-post/104203/8 "2023-09-25T18:29:26Z")

</div>

@juliohm I have no Linux laptop currently (the one I had is dead) and it’s a bit annoying to work with Windows.

Moreover I’m a bit lost regarding this potential PR. I don’t know where to start. Should we preliminarily define a path primitive? Should we consider whether it is closed from an argument given by the user or should we rather detect whether it is closed?

And what about the method implemented by @empet? Should we do a method for a given differentiable function and another method (mine) for a discrete path?

---

<div class="post-metadata">

**Author:** ![\_stla](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/_stla/32/35613_2.png) [@\_stla](https://discourse.julialang.org/u/_stla)\
**Post date:** [September 25, 2023, 6:37pm UTC](https://discourse.julialang.org/t/drawing-a-tubular-path-with-meshes-jl-blog-post/104203/9 "2023-09-25T18:37:06Z")

</div>

@empet Off-topic but your avatar reminds me this picture:

[https://raw.githubusercontent.com/stla/RcppColors/main/inst/images/KleinRt5\_smooth.gif(image larger than 4 MB)](https://raw.githubusercontent.com/stla/RcppColors/main/inst/images/KleinRt5_smooth.gif)

Is it based on the Klein j-invariant function?

---

<div class="post-metadata">

**Author:** ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)\
**Post date:** [September 25, 2023, 6:40pm UTC](https://discourse.julialang.org/t/drawing-a-tubular-path-with-meshes-jl-blog-post/104203/10 "2023-09-25T18:40:46Z")

</div>

Regarding paths, we have the `BezierCurve` primitive for 2D and 3D paths, which can be sampled at any parameter value t in [0, 1]. It has the `isclosed` trait implemented already.

For discrete path we have the `Rope` and `Ring`, which are types of polygonal `Chain`. They also have the `isclosed` trait implemented.

Given these two paths we just need to expand laterally to produce the tube. So the `Tube` struct could take a `path` field and another field representing the shape, and then produce the tube. What do you think?

@empet you don’t need to know Git to contribute, you can go to the repository and press “.” on the keyboard to start editing the files on GitHub directly.

---

<div class="post-metadata">

**Author:** ![\_stla](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/_stla/32/35613_2.png) [@\_stla](https://discourse.julialang.org/u/_stla)\
**Post date:** [September 25, 2023, 6:45pm UTC](https://discourse.julialang.org/t/drawing-a-tubular-path-with-meshes-jl-blog-post/104203/11 "2023-09-25T18:45:10Z")

</div>

Hmm looks good.

@empet You can do “.” as said by Julio or we can also help you for git if you want to contribute. This would be an opportunity to learn, and this is not complicated.
