Juliaと3Dプリント (モデリング編)

ほりたみゅ/@Hyrodium/堀川由人
JuliaTokai#21 (2025-03-30)

目次

  • 自己紹介
  • 3Dプリントざっくり入門
  • Juliaでモデリング
  • 印刷例の紹介
  • 今後の予定

自己紹介 (1/2: Julia関連)

最近ちょっとJuliaから遠ざかってしまってました 🙏

自己紹介 (2/2: 3Dプリント関連)

目次

  • 自己紹介
  • 3Dプリントざっくり入門
  • Juliaでモデリング
  • 印刷例の紹介
  • 今後の予定

3Dプリントざっくり入門 (1/2: 3Dプリンタの種類)

家庭用で使えるのは大きく分けて2種類ある

  • 熱溶解積層方式 (FDM)
    • フィラメントを熱で溶かして積層する方式
    • 👍 フィラメントの種類が豊富 (PLA, PETG, TPU, ASA, ABS, etc.)
    • 👎 積層痕が目立つ
  • 光造形方式 (SLA)
    • 液体樹脂(レジン)をUVで硬化させて積層する方式
    • 👍 高精度
    • 👎 レジンの管理が面倒

3Dプリントざっくり入門 (2/2: 3Dプリンタの選定)

どの3Dプリンタを購入するのが良いか?

新しく買うなら BaumbLab の製品がオススメ
ただし不合理なファームウェア改悪の話があるので別のメーカーの方が良いかも

目次

  • 自己紹介
  • 3Dプリントざっくり入門
  • Juliaでモデリング
  • 印刷例の紹介
  • 今後の予定

Juliaでモデリング (1/4: 以前の関連発表)

Juliaでモデリング (2/4: なぜJuliaでモデリング?)

普通はCADツール等を使ってモデリングする (e.g. Onshape, FreeCAD, Blender)

Juliaのメリット

  • アルゴリズムに基づいた形状を生成できる
  • 数式に基づいた形状を生成できる
  • 既存の資産(e.g. BasicBSpline.jl)が使える!

Juliaでモデリング (3/4: BasicBSpline.jl)

  • BasicBSpline.jl
    • B-splineを扱うためのJuliaパッケージ
    • 数学的な整合性を重視して基礎的なツールや関数を提供
  • B-splineとは?
    • 区分多項式を使って関数を近似するための道具
    • 基底関数が区分多項式空間の基底で、その線型結合で関数近似していく
    • NURBS: Non-Uniform Rational B-Spline (一般化したやつ)

Juliaでモデリング (4/4: データ形式)

3Dモデルとして使われる主なデータ形式2種類:

  • STL
    • 三角形メッシュのデータ形式
    • 仕様は単純で簡単に読み書きできる
  • STEP
    • CAD向きの柔軟なデータ形式
    • 滑らかな曲面(円柱, B-spline, NURBS)にも対応
    • 仕様は複雑で、読み書きが大変

今回はBasicBSpline.jlからSTEP形式の出力をやっていき 💪

Juliaでモデリング (5/5: STEP出力)

STEP出力にはgenerate_step_script関数を呼べばOK

MWE (minimal working example)

using BasicBSpline  # PR393の機能が必要
using StaticArrays
include("generate_step_script.jl")  # from gist
P = BSplineSpace{1}(KnotVector([0,0,1,1]))
a = [SVector(x,y,z) for x in 0:1, y in 0:1, z in 0:1]
M = BSplineManifold(a, P, P, P)
write("mwe.step", generate_step_script(M))

目次

  • 自己紹介
  • 3Dプリントざっくり入門
  • Juliaでモデリング
  • 印刷例の紹介
  • 今後の予定

印刷例の紹介 (1/8: 一覧)

(もっとexampleを作りたかったが…間に合わず🙏)

印刷例の紹介 (2/8: 螺旋状正方形①)

螺旋に沿って正方形を回転させたやつ (BasicBSpline.jlのドキュメント)

k1 = k2 = KnotVector([0,0,1,1])
k3 = UniformKnotVector(-6:6)
P1 = BSplineSpace{1}(k1)
P2 = BSplineSpace{1}(k2)
P3 = BSplineSpace{3}(k3)
e₁(t) = SVector(cos(t),sin(t),0)
e₂(t) = SVector(-sin(t),cos(t),0)
a = cat([[e₁(t)*i+e₂(t)*j+SVector(0,0,t) for i in 0:1, j in 0:1] for t in -2:0.5:2]..., dims=3)/40
M = BSplineManifold(a,(P1,P2,P3))
plot(M; colorbar=false)
script = generate_step_script(M)
write("example.step", script)

上記スクリプトでプロットとSTEP出力ができる

印刷例の紹介 (3/8: 螺旋状正方形②)

制御点をランダマイズ→花瓶モード印刷

印刷例の紹介 (4/8: 擬球面①)

a_D = [SVector(x,y)*ifelse(iszero(x*y),2.0,1.0) for x in -1:1, y in -1:1]
w_D = [ifelse(iszero(x*y),1/sqrt(2),1) for x in -1:1, y in -1:1]
k_D = KnotVector([-1,-1,-1,1,1,1])
P_D = BSplineSpace{2}(k_D)
tractrix_x(t) = sech(t)
tractrix_y(t) = t-tanh(t)
tractrix_y′(t) = 1-1/cosh(t)^2
function tractrix_y⁻¹(y)
    y == 0.0 && return zero(float(y))
    t = y
    for _ in 1:20
        t = t - (tractrix_y(t)-y)/tractrix_y′(t)
    end
    return t
end
Py = BSplineSpace{3}(KnotVector([0;0;0;(0:0.05:1).^2;1;1;1]*3))
a_r = fittingcontrolpoints(tractrix_x∘tractrix_y⁻¹, Py)
a_y = fittingcontrolpoints(x->x, Py)
plot(BSplineManifold(SVector.(a_r,a_y), Py))
a_P = [push(p/sqrt(2)*r,y) for p in a_D, (r,y) in zip(a_r,a_y)]
w_P = [w for w in w_D, (r,y) in zip(a_r,a_y)]
M_P = RationalBSplineManifold(a_P/20,w_P,P_D,P_D,Py)
plot(M_P)
script = generate_step_script(M_P)
write("pseudosphere.step", script)

印刷例の紹介 (5/8: 擬球面②)

  • B-spline多様体の定義域は矩形領域
  • 微分不能の箇所がある

印刷例の紹介 (6/8: 擬球面③)

印刷例の紹介 (7/8: 直方体なみなみ側面①)

k1 = k2 = KnotVector(-12:12)
k3 = UniformKnotVector(0:12)
P1 = BSplineSpace{3}(k1)
P2 = BSplineSpace{3}(k2)
P3 = BSplineSpace{3}(k3)
a = [SVector(x,y,z) for x in -10:10, y in -10:10, z in 0:8] / 300
w = fill(1, dim(P1), dim(P2), dim(P3))
M = RationalBSplineManifold(a,w,P1,P2,P3)
M = BasicBSpline.clamp(M)
a = controlpoints(M)
a[begin, begin+1:end-1, begin+1:end-1] .-= [SVector(ifelse(iseven(i+j), 0.0, 0.005), 0.0, 0.0) for i in 1:19, j in 1:7]
a[end, begin+1:end-1, begin+1:end-1] .+= [SVector(ifelse(iseven(i+j), 0.0, 0.005), 0.0, 0.0) for i in 1:19, j in 1:7]
a[begin+1:end-1, begin, begin+1:end-1] .-= [SVector(0.0, ifelse(iseven(i+j), 0.0, 0.005), 0.0) for i in 1:19, j in 1:7]
a[begin+1:end-1, end, begin+1:end-1] .+= [SVector(0.0, ifelse(iseven(i+j), 0.0, 0.005), 0.0) for i in 1:19, j in 1:7]
M = RationalBSplineManifold(a,w,bsplinespaces(M))
plotlyjs()
plot(M)

script = generate_step_script(M)
write("naminami.step", script)

印刷例の紹介 (8/8: 直方体なみなみ側面②)

目次

  • 自己紹介
  • 3Dプリントざっくり入門
  • Juliaでモデリング
  • 印刷例の紹介
  • 今後の予定

今後の予定 (1/5: まとめ)

  • BasicBSpline.jlで定義した形状のSTEP出力した
  • STEPファイルから3Dプリントした
  • 通常のCADでモデリングしにくい形状も出力可能 (擬球面, 直方体なみなみ側面)

しかし問題点は残る…

  • 生成できる形状の少なさ
  • 不正なSTEPファイルの疑惑

今後の予定 (2/5: 生成できる形状の少なさ)

  • 直方体と同相な形状しか出力できない
    • 現状ではBSplineManifold{3}RationalBSplineManifold{3}のみ対応
  • 出力できない形状の例
    • Y字のような分岐形状
    • トーラスのような穴のある形状
  • GUIが必要なほど複雑形状は不要だが、もう少し複雑な形状は扱いたい
    • B-spline閉曲線で囲まれた領域の押し出し・回転
    • 複数のB-spline曲面の貼り合わせ

今後の予定 (3/5: 不正なSTEPファイルの疑惑①)

STEPファイルの仕様は難しい!

  • 仕様自体の難しさではなく仕様が確認しにくい📃
  • ISO 10303で規定されているが、閲覧は有料💸
  • 個人開発向けの解説資料が見当たらず🥲
  • 他のCADツールで出力されたSTEPファイルを読んで仕様を推測する作業が発生🤯

その結果…正しいSTEPファイルが出力できてないっぽい

今後の予定 (4/5: 不正なSTEPファイルの疑惑②)


  • FreeCAD・Onshapeでは読み込めるがOrcaSlicerで読み込み失敗しがち
  • 正常に読み込んでSTEP再出力して問題回避は可能

今後の予定 (5/5: 告知など)