💬

Fusion360で数式を使った曲線の描き方

に公開

背景

風洞のノズルを設計するにあたり、ノズルの曲線は基本的に数式で描かれます。
普段CADとしてFusion360を使用していますが、基本機能としてはこのような機能がないため、色々調べてみました。
fusion360EquationCurveというのがあったので、試してみました
https://github.com/stanfordroboticsclub/fusion360EquationCurve

スクリプトの設定

githubからダウンロードして、解凍し、ドキュメント/Fusion360/scripts/の中に移動させます。
ユーティリティ->アドイン->スクリプトとアドインを選択

スクリプトタブのマイスクリプトのプラス部分をクリックすると、フォルダの選択画面に移ります


これでマイスクリプトに反映されます

操作方法

CurveFromEquationをダブルクリックしてスクリプトを起動します


デフォルトのままOKを押してみましたが、私の環境だと何も変化がなく、何も描けませんでした。
本来だったら、このスクリプトなんて使わないで、別のスクリプトを探すのですが、ちょっと興味が湧いたので、調べてみました。

デバッグ


スクリプトとアドインの右下の実行ボタンのところをデバッグにすると、VSCodeが立ち上がります

どこで引っかかっているのか確認したところ、astevalの挙動がおかしいことがわかりました。
ということで、astevalの変わりにevalを使って書き換えてみました。
CurveクラスのbuildCurve関数の部分だけ書き換えました。

CurveFromEquation.py
class Curve:
    def __init__(self):
        self.curveName = defaultCurveName
        self.xFunction = defaultCurveFunctionX
        self.yFunction = defaultCurveFunctionY
        self.zFunction = defaultCurveFunctionZ

        self.tStart = defaultTStart
        self.tEnd = defaultTEnd
        self.tStep = defaultTStep

    def buildCurve(self):
        global newComp
        newComp = createNewComponent()
        if newComp is None:
            ui.messageBox('New component failed to create', 'New Component Failed')
            return

        product = app.activeProduct
        design = adsk.fusion.Design.cast(product)
        unitsMgr = design.unitsManager

        # Create a new sketch.
        sketches = newComp.sketches
        xyPlane = newComp.xYConstructionPlane

        aeval = Interpreter()
        aeval.symtable['pi'] = math.pi

        points = adsk.core.ObjectCollection.create()

        '''
        try:
            for time in frange(aeval(self.tStart), aeval(self.tEnd), aeval(self.tStep)):
                aeval.symtable['t'] = time
                x = unitsMgr.convert(aeval(self.xFunction), unitsMgr.defaultLengthUnits, "internalUnits")
                y = unitsMgr.convert(aeval(self.yFunction), unitsMgr.defaultLengthUnits, "internalUnits")
                z = unitsMgr.convert(aeval(self.zFunction), unitsMgr.defaultLengthUnits, "internalUnits")

                point = adsk.core.Point3D.create(x,y,z)
                points.add(point)
        except:
            print('something wrong')
        
        
        '''
        safe_dict = {'pi': math.pi, 'sin': math.sin, 'cos': math.cos, 'tan': math.tan, 'sqrt': math.sqrt, 'log': math.log}
        try:
            t_start = eval(self.tStart, {"__builtins__": None}, safe_dict)
            t_end = eval(self.tEnd, {"__builtins__": None}, safe_dict)
            t_step = eval(self.tStep, {"__builtins__": None}, safe_dict)

            for time in frange(t_start, t_end, t_step):
                safe_dict['t'] = time
                x = unitsMgr.convert(eval(self.xFunction, {"__builtins__": None}, safe_dict), unitsMgr.defaultLengthUnits, "internalUnits")
                y = unitsMgr.convert(eval(self.yFunction, {"__builtins__": None}, safe_dict), unitsMgr.defaultLengthUnits, "internalUnits")
                z = unitsMgr.convert(eval(self.zFunction, {"__builtins__": None}, safe_dict), unitsMgr.defaultLengthUnits, "internalUnits")

                point = adsk.core.Point3D.create(x, y, z)
                points.add(point)
        except Exception as e:
            ui.messageBox(f"評価エラー: {e}")
            return

        
        newComp.name = self.curveName
        sketch = newComp.sketches.add(newComp.xYConstructionPlane)
        sketch.name = self.curveName 

        try:
                sketch.sketchCurves.sketchFittedSplines.add(points)
                # sketch.sketchCurves.sketchLines.addByTwoPoints(vertices[(i+1) %6], vertices[i])
        except:
            print('something wrong')




def run(context):
    try:
        product = app.activeProduct
        design = adsk.fusion.Design.cast(product)
        if not design:
            ui.messageBox('It is not supported in current workspace, please change to MODEL workspace and try again.')
            return
        commandDefinitions = ui.commandDefinitions
        #check the command exists or not
        cmdDef = commandDefinitions.itemById('Equation Curve')
        if not cmdDef:
            cmdDef = commandDefinitions.addButtonDefinition('Equation Curve',
                    'Create curve from equation',
                    'Create sketch curve from parametric equation')

        onCommandCreated = CurveCommandCreatedHandler()
        cmdDef.commandCreated.add(onCommandCreated)
        # keep the handler referenced beyond this function
        handlers.append(onCommandCreated)
        inputs = adsk.core.NamedValues.create()
        cmdDef.execute(inputs)

        # prevent this module from being terminate when the script returns, because we are waiting for event handlers to fire
        adsk.autoTerminate(False)
    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))


確認


無事動くことがわかりました
これで数式を使って曲線を描くことができます

Discussion