C#ATIA

↑タイトル詐欺 主にFusion360API 偶にCATIA V5 VBA(絶賛ネタ切れ中)

3D曲線のパイプの中心線を求める2

こちらの続きです。
3D曲線のパイプの中心線を求める1 - C#ATIA

前回は惨敗だったので作戦変えます。
・・・細かな事は省力しますが、忘れちゃいそうなので
書き残しておきたいことがあるので、そっちがメインなお話です。

こんな感じで、パイプ形状から中心線を作る為の大量の点を
取得する事には成功しました。

問題はここからです。大量の点⇒大量の通過点を持つスプライン
を行えば中心線の完成なのですが、通過点からスプラインの生成は
スケッチを経由して作るしか方法を知りません。

スケッチの処理は時間がかかるので避けたいのですが、他の方法が
無いため、スケッチ経由でスプラインを生成しました。
単調なスクリプトで開発しているのですが、スクリプト上では
問題ありません。

しかし、アドインに組み込むと思うような動作をしてくれません
でした。推測ですが、inputChangedイベント内でスケッチを
作成したり削除したりを行う事が悪いのだろうと思います。

・・・諦めれば良いのですが、通過点から3DのNurbs曲線を
作成出来るものを探してみたところ、こちらを見つけました。
GitHub - orbingol/NURBS-Python: Object-oriented pure Python B-Spline and NURBS library
有難い事に、他のモジュール類に依存していなさそうです。


問題は、Fusion360APIで外部モジュールの利用方法です。
pipでインストールするとFusion360APIで利用されるPython
フォルダにモジュールがインストールされると思うのですが、
Updateの際に対応出来なくなると思われます。
その為、ローカルの別の場所(スクリプトフォルダ内等)に
モジュールを置き呼び出したいのです。

で、手順。vscodeスクリプトの編集を行っている状態です。
・pipをupdate。(これを行わなかった為、一回目は失敗しました)
vscodeのターミナルで、"pip install geomdl" (--user あった方が良いのかな・・・)
 "pip3 install --user geomdl" としました。
 これでインストール完了。
 但し、良く調べたらFusion360でインストールされたpythonとは
 異なるところにインストールされました・・・。
vscodeのターミナルで、"pip show geomdl" でインストールフォルダを探す。
pipでインストールしたパッケージの場所を調べる - Qiita
”geomdl” フォルダをコピーし任意のフォルダにペーストする。
 ”geomdl” と ”geomdl-5.3.1.dist-info” フォルダをコピーし
 任意のフォルダにペーストする。
 これで取りあえずの目的は達成です。
vscodeのターミナルで、"pip uninstall geomdl" でアンインストール。
 配布時を考慮するとパスの通っている位置のモジュールを
 削除して開発・テストを行いたいので。
で、大丈夫そうです。多分。
※どのモジュールでもこの方法で出来るわけでは無いと思います。


実際にテストするためにこちらを作成しました。

# Fusion360API Python script

import traceback
import adsk.fusion
import adsk.core
import sys
import pathlib

# nurbs-pythonのインポート
# https://nurbs-python.readthedocs.io/en/5.x/index.html
parent_dir = pathlib.Path(__file__).resolve().parent
target_dir = parent_dir / 'Modules'
sys.path.append(str(target_dir))
from geomdl import BSpline
from geomdl import utilities
del sys.path[-1]

def run(context):
    ui = adsk.core.UserInterface.cast(None)
    try:
        app: adsk.core.Application = adsk.core.Application.get()
        ui = app.userInterface

        curve = BSpline.Curve()
        curve.degree = 7
        curve.ctrlpts = [
            [1, 0, 0], 
            [1, 5, 0], 
            [2, -1, 3], 
            [1, 1, 0],
            [3, 0, 1], 
            [5, 1, 2], 
            [7, -6, 1], 
            [9, 1, 2],
        ]

        curve.knotvector = utilities.generate_knot_vector(
            curve.degree,
            len(curve.ctrlpts)
        )

        crv: adsk.core.NurbsCurve3D = toNurbsCurve(curve)

        dumpCurves3D([crv])

    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))


def toNurbsCurve(
    crv: 'curve') -> adsk.core.NurbsCurve3D:

    pnt3D: adsk.core.Point3D = adsk.core.Point3D
    controlPoints = [pnt3D.create(c[0], c[1], c[2]) for c in crv.ctrlpts]
    degree = crv.degree
    knots = crv.knotvector
    isPeriodic = crv.rational

    nurbs: adsk.core.NurbsCurve3D = adsk.core.NurbsCurve3D.createNonRational(
        controlPoints,
        degree,
        knots, 
        isPeriodic
    )

    return nurbs


def dumpCurves3D(curves, name = ''):
    app: adsk.core.Application = adsk.core.Application.get()
    des: adsk.fusion.Design = app.activeProduct
    root: adsk.fusion.Component = des.rootComponent

    skt: adsk.fusion.Sketch = root.sketches.add(root.xYConstructionPlane)
    if len(name) > 0:
        skt.name = name

    skt.isComputeDeferred = True
    for c in curves:
        if hasattr(c, 'asNurbsCurve'):
            c = c.asNurbsCurve
        skt.sketchCurves.sketchFixedSplines.addByNurbsCurve(c)
    skt.isComputeDeferred = False

最初に "NURBS-Python"(geomdl)のモジュールをインポート
しなければならないのですが、sys.pathにパスを追加して
から行ってます。

処理的には、"NURBS-Python" でnurbsカーブを作成し、
その情報からFusion360用のnurbsカーブを作成し
スケッチに書き出しています。

実際に実行したところ出来ました。

”・・・はぁ?で?” と言うレベルな事は分かってます。

これはコントロールポイントでNurbsカーブを作成して
いるのですが、通過点では無いため目的を果たしていません。

でも、こちらにフィッティングの例があるので
出来るような気がしてます。
Curve & Surface Fitting — NURBS-Python 5.3.1 documentation
新たな武器を手に入れちゃったな。
スケッチ経由より速そうだし。