[FreeCAD使い方講座] Pythonコンソールから操作する方法② ~ Draftでべシェ曲線・Bスプライン曲線を描く


2021/02/12

前回はFreeCAD内部で利用するpythonコンソールからの簡単な操作の概要を記事として書きましたが、今回もFreeCAD内でPythonスクリプティングのお勉強をしていきます。前回の続きの内容として、DraftベンチのPythonスクリプトの操作方法と、曲線の描き方を特集します。


pythonスクリプトで曲線を描くメリット

曲線の立体物を作成するとなると、定規を当てて寸法を測ることも出来ないので、なかなか手で制御しながら描いていくのは難しいものです。

FreeCADの強力なツールであるpythonスクリプトで曲線の制御点を指定しながらモデリングすると、全ての操作をスクリプトで管理することができるので、柔軟な形状が作成することも可能であり、モデリングの再現性も拡張性も高くなり、かなりいいこと尽くめです。

特に、流体工学などの流線型のデザイン設計で役に立つテクニックと言えます。

FreeCADにはベシェ曲線とBスプライン曲線の主に2つの曲線作成機能がありますが、今回はこの2つを比較しながら簡単なpythonスクリプティングの基礎を説明していきます。


べシェ曲線とBスプライン曲線

少し制御点付きの曲線作成の話を始めるにあたって、理屈の方を先に軽く触れておきたいと思います。

Draftベンチでべシェ曲線

ベシェ曲線に関しては、こちらの図解されているページ(参考サイト:一から学ぶベジェ曲線)が分かりやすいと思います。

ここでは3点(
P1,P2,P3P_1, P_2, P_3)で構成される2次のベシェ曲線B1,2,3B_{1,2,3}を使って、FreeCADのベシェ曲線を考察します。

{B1,2,3(t)=(1t)B1,2(t)+tB2,3(t),B1,2(t)=(1t)P1+tP2,B2,3(t)=(1t)P2+tP3,\displaystyle \begin{cases} B_{1,2,3}(t) = (1-t) B_{1,2}(t) + t B_{2,3}(t), \\ B_{1,2}(t) = (1-t) P_1 + t P_2, \\ B_{2,3}(t) = (1-t) P_2 + t P_3, \\ \end{cases}Eq. (3points-bezier)

FreeCADではDraftベンチに切り替えて、ベシェ曲線ツールを選択することでベシェ曲線を描くことができます。

合同会社タコスキングダム|蛸壺の中の工作室

手始めに適当に以下のような3点のベシェ曲線を手動で作成して、pythonコンソールからどのようなメソッドで構成されているかを確認してみます。

ベシェ曲線にツールを押して、3点を適当な位置に連続してマウスをクリックし、最後にEscキーで図形作成を確定していきます。

合同会社タコスキングダム|蛸壺の中の工作室

すると以下のような出力がコンソールが得られていると思います。

            points = [FreeCAD.Vector(0.0,0.0,0.0),FreeCAD.Vector(5.0,6.0,0.0),FreeCAD.Vector(10.0,0.0,0.0)]
bez = Draft.makeBezCurve(points,closed=False,support=None)
Draft.autogroup(bez)
        
ここでpointsという点を示すFreeCAD.Vectorクラスの要素が入る配列が、先程マウスで選択していった点をキャプチャしているようです。また、この配列の最初の要素が始点、最後の要素が終点で、この点はベシェ曲線の性質上必ず線上に乗る点になりますが、配列の最初の点と最後の点以外の中間要素は全て制御点を表すことになります。

曲線をスクリプトで使うやり方としては、
pointsという配列を定義してからDraft.makeBezCurveを呼び出すようです。

DraftベンチでBスプライン曲線

先程の3点で構成されたベシェ曲線のときと比較するために、同じ3点でBスプライン曲線を作成してみます。

Bスプライン曲線の理論はベシェ曲線よりも複雑です。正確にはベシェ曲線をより一般化することでB-スプライン曲線が得られるようです。

Bスプライン曲線は個数
ii個の制御点{Pi}\{ P_i \}とノット列{ti}\{ t_i \}によって定義される複数の多項式曲線を接続して1本の曲線としたものです。

Bスプラインの理解する上で重要なのが、ノット列と呼ばれる点の動く範囲を表すパラメータ
ttの集合{t0,t1,t2,}\{ t_0, t_1, t_2, \dots \}なのですが、このノット列を使って描かれるnn次のBスプラインの基底関数とは以下のような漸化式で定義されます。

Nin(t)=ttiti+ntiNin1(t)+ti+n+1tti+n+1ti+1Ni+1n1(t)\displaystyle N_i^n(t) = \frac{t - t_i}{t_{i+n} - t_i} N_i^{n-1}(t) + \frac{t_{i+n+1} - t}{t_{i+n+1} - t_{i+1}} N_{i+1}^{n-1}(t)Eq. (N-base-func)

このとき0次の基底関数はノット列に対して、

Ni0(t)={1if t[ti,ti+1)0if t[ti,ti+1)\displaystyle N_i^0(t) = \begin{cases} 1 &\text{if } t \in [ t_i, t_{i+1} ) \\ 0 &\text{if } t \notin [ t_i, t_{i+1} ) \end{cases}Eq. (0-base-func)

を満たします。つまりゼロ次のときには制御点の影響を及ぼす範囲が独立していることを意味しています。

これが1次になると、たとえばノット列の
{t0,t1,t2}\{ t_0, t_1, t_2 \}だけの範囲に着目すると、

Ni1(t)={tif t[t0,t1)2tif t[t1,t2)0if t[t0,t2)\displaystyle N_i^1(t) = \begin{cases} t &\text{if } t \in [ t_0, t_1 ) \\ 2 - t &\text{if } t \in [ t_1, t_2 ) \\ 0 &\text{if } t \notin [ t_0, t_2 ) \end{cases}Eq. (1-base-func)

と出来ます。つまり1次のBスプラインは各制御点を順番に直線で繋いだ操作と等しいようです。

さらに2次になると、ノット列の
{t0,t1,t2,t3}\{ t_0, t_1, t_2, t_3 \}だけの範囲に着目して、

Ni2(t)={12t2if t[t0,t1)t2+3t32if t[t1,t2)12(t3)2if t[t2,t3)0if t[t0,t3)\displaystyle N_i^2(t) = \begin{cases} \frac{1}{2}t^2 &\text{if } t \in [ t_0, t_1 ) \\ -t^2 + 3t -\frac{3}{2} &\text{if } t \in [ t_1, t_2 ) \\ \frac{1}{2} (t-3)^2 &\text{if } t \in [ t_2, t_3 ) \\ 0 &\text{if } t \notin [ t_0, t_3 ) \end{cases}Eq. (2-base-func)

のようになり、制御点の影響は2点先まで広がります。

3次以上の基底関数の紹介は省きますが、一般に
nn次の場合にはnn点先までの制御点の影響を考慮するという具合にノット列が定まります。

FreeCADのBスプライン機能はというと、ソースコードは詳しく確認しておりませんが、2点先までの制御点が影響を受けるような挙動を示しますので、おそらくデフォルトでは2次のBスプライン曲線を念頭に設計されているものと推測します。

Bスプライン曲線でいうセグメント数
LLとは、nn次のBスプライン曲線を描きたい場合において、その制御点数n+Ln + Lを満たすような数です。たとえば制御点3つP0,P1,P2P_0, P_1, P_2のときで構成されるセグメント数1の2次Bスプラインの式は以下の通りです。

P(t)=N02(t)P0+N12(t)P1+N22(t)P2\displaystyle P(t) = N_0^2(t) P_0 + N_1^2(t) P_1 + N_2^2(t) P_2Eq. (3points-bspline)

このようにBスプライン曲線を理屈付けすると、ベシェ曲線よりもはるかに難解なものになりますが、スクリプトでモデリングする場合には実はBスプラインのほうが使いやすいことを、こちらも3点でBスプライン曲線を検証してみます。

まず先ほどと同じ手順でDraftベンチからBスプライン曲線を描いてみましょう。

合同会社タコスキングダム|蛸壺の中の工作室

ベシェ曲線を使ったときと比べて見た目で大きく違うのが、中間の制御点(ここで言うと2点目)が曲線近傍を通過していることです。

モデリングする側からすると、中間制御点を大きく逸脱する形状になるベシェ曲線よりは、制御点の近くで曲線を形成してくれるBスプライン曲線のほうが、最終的な図形をイメージしやすいメリットがあります。

このときに得られたpythonコンソールの出力も確認すると、

            points = [FreeCAD.Vector(0.0,0.0,0.0),FreeCAD.Vector(5.0,6.0,0.0),FreeCAD.Vector(10.0,0.0,0.0)]
spline = Draft.makeBSpline(points,closed=False,face=False,support=None)
Draft.autogroup(spline)
        
となっています。

先程のベシェ曲線の場合同様、Bスプライン曲線もほぼ同じですが、スクリプトとしては
pointsという配列を定義してからDraft.makeBSplineを呼び出すようです。


曲線スクリプトを作成

ここからはFreeCADからPythonスクリプトを実行して、簡単な図形を出力させてみます。

先程説明したとおりで、スクリプトで図形を描く場合Bスプライン曲線で描いたほうが完成形状が想像しやすいので、ここではBスプラインをベースにスクリプトモデリングを行います。

今回はpythonコンソールからではなく、マクロから呼び出して利用してみます。

以下のスクリプトを
bspline.pyとして保存しておきます。

            import FreeCAD
import Draft

App.newDocument("my_doc")

points = [FreeCAD.Vector(0.0,0.0,0.0),FreeCAD.Vector(5.0,6.0,0.0),FreeCAD.Vector(10.0,0.0,0.0)]
spl = Draft.makeBSpline(points,closed=False,face=False,support=None)
Draft.autogroup(spl)

#👇ファイルの保存先(絶対パスで指定) --> /home/user/ドキュメント/bspline.FCStd
App.getDocument("my_doc").saveAs("/home/user/ドキュメント/bspline.FCStd")
        
このスクリプトを適当な場所に保存し、FreeCAD側から呼び出してみます。

ツールメニューから
[記録されたマクロを開くためのダイアログボックスを開く]のアイコンをクリックし、[マクロの実行]ダイアログを開きます。

合同会社タコスキングダム|蛸壺の中の工作室

[ユーザーマクロの場所]から先ほど作っておいたbspline.pyのあるフォルダを開くと、ユーザーマクロのリストにスクリプトが表示されますので、これを選択し、[実行]ボタンを押します。

合同会社タコスキングダム|蛸壺の中の工作室

正しく実行されると、Draftベンチ上で曲線が描かれ、指定した保存先に
bspline.FCStdが出力されていると思います。

余談 ~ freecadcmdからBスプラインは使えない

FreeCADにはターミナルから呼び出せるCLI用のハンディなコマンドfreecadcmdが使えるようになっています。

このfreecadcmdで注意が必要なのが、内部でQtを使っているようなグラフィカル関数が使えないので、今回の例で言えば、ベシェ曲線は使えても、Bスプラインは使えません。

たとえば上記の
bspline.pyをfreecadcmdで叩くと、

            $ freecadcmd bspline.py
FreeCAD 0.18, Libs: 0.18R
(c) Juergen Riegel, Werner Mayer, Yorik van Havre 2001-2019
  #####                 ####  ###   ####  
  #                    #      # #   #   # 
  #     ##  #### ####  #     #   #  #   # 
  ####  # # #  # #  #  #     #####  #   # 
  #     #   #### ####  #    #     # #   # 
  #     #   #    #     #    #     # #   #  ##  ##  ##
  #     #   #### ####   ### #     # ####   ##  ##  ##

Exception while processing file: draft.py ['module' object has no attribute 'UiLoader']
        
という出力で正しく実行されません。

FreeCADのBスプラインの実装の一部に、Qtのライブラリを読み込む箇所があり、それがコマンドラインからでは使えないということです。


まとめ

今回はPythonスクリプトによるDraftベンチと曲線の生成方法を主に解説していきましたが、ドラフトだけでは3dモデルを作ったことになりません。

次回以降で、今回のテクニックを使ってより立体的にするための3dモデルで部品を作成するような手順を説明して行く予定です。
記事を書いた人

記事の担当:taconocat

ナンデモ系エンジニア

電子工作を身近に知っていただけるように、材料調達からDIYのハウツーまで気になったところをできるだけ細かく記事にしてブログ配信してます。