C#ATIA

↑タイトル詐欺 主にCATIA V5 の VBA(最近はPMillマクロとFusion360APIが多い)

CAD Assistant

Open Cascadeカーネルの3Dビューアー/コンバーターだそうです。
CAD Assistant | OPEN CASCADE

結構前からリリースされていたっぽいです。
要登録ですが、商用可だそうです。

動作は軽いです。
f:id:kandennti:20200225155444p:plain
見た目は2・3世代ぐらい前の感じです。

f:id:kandennti:20200225155619p:plain
エクスポート出来るフォーマットですが、
実質IgesとStepぐらいかな?

SubList

こちらの質問の意味がわかり、回答を知っていたので答えてみました。
Speed up 'Component Activation State' parameter setting - DASSAULT: CATIA products - Eng-Tips

アクティブなファイルが複雑なデータ程、パラメータへのアクセスが重くなり
結果的に質問者さんのように処理が重くなってしまうのが、CATIAの運命の様です。

但しパラメータ群をSubListで一旦区切ってしまえば、パラメータ名を使用し
Itemでズバリ取得可能な上、大幅に処理が軽くなるはずです。
(今回はProduct毎に区切りました)


確か、バッチモードで処理するとさらに軽くなるような記述を読んだ覚えが
あるのですが、そこまでしなくても十分なはず。
(大量のDrawファイルから特定のパラメータを取得したい場合は、バッチモードが
早いぞ! って書いてあった記憶です。)


連日、VBAのリハビリみたいになっているなぁ。

手抜きマクロ起動用メニュー4

こちらの続きです。
手抜きマクロ起動用メニュー3 - C#ATIA

GrabCADにUpしていましたが、管理が出来ない為Github
移動しました。
GitHub - kantoku-code/CATIA_V5_SimpleMacroMenu: Form buttons for calling macros created for each module are created dynamically.

時に変更点はありません。

MSAPC.Apc

手元にこちらのコードがあったので、
実行中のプロジェクト名とパス取得する - C#ATIA

こちらに投げてみました。
CATIA VBA - Active Macro Path - DASSAULT: CATIA products - Eng-Tips

意外でした、あのLittle Cthulhu氏が知らなかったなんて・・・。


Eng-TipsのCATIAでも3DExの話題がチラホラ出ているので、
もうついていけないかなぁ。

複合加工機

色々とやらなきゃいけない事と、やりたい事があり、結局一番やりたくも無く
必要でも無いことを片し続けているという、負のスパイラルに陥ってます。
(ありますよね?)

ひょっとしたら会社で複合加工機を購入するかもしれない・・・。
取り組みそうな人間がいない為、僕がモルモット的なポジションになりそう。
(予めお断りしますが、動物愛護団体関係の皆様。あくまで言葉の綾です・・・)

5軸やら複合機やら、異国の話だと思っていたのに。
勉強しなきゃ。CAM無いから、当面Fusion360で練習かな?

俺コマンドを作る3

こちらの続きです。
俺コマンドを作る2 - C#ATIA

先日の俺コマンドを清楚に実装出来るように考えたのですが、
結果としてこちらの類似したものを作ることになりそうなため
止めました・・・。
github.com


一番困っていたのは、「Fusion360CommandBase.py」で対応していない
イベント処理の追加の仕方だったのですが、普通に行ったところ
出来ることが分かったので、こちらで行くことにします。


とりあえず、こちらのサンプルを「Fusion360AddinSkeleton」で
実装することにします。こちらは未対応な「PreSelect」イベントを使っています。
GitHub - kantoku-code/Fusion360-SelectFilter_T_Sample: Fusion360API Python script


「Demo1Command.py」を修正した「OreCommand.py」はこんな感じです。

import adsk.core
import adsk.fusion
import traceback

from .Fusion360Utilities.Fusion360Utilities import AppObjects
from .Fusion360Utilities.Fusion360CommandBase import Fusion360CommandBase

class OreCommand(Fusion360CommandBase):
    handlers = []
    def on_create(self, command: adsk.core.Command, inputs: adsk.core.CommandInputs):

        onPreSelect = PreSelectHandler()
        command.preSelect.add(onPreSelect)
        self.handlers.append(onPreSelect)

        selSktCon = inputs.addSelectionInput(
            'selection_input_id', 
            'PreSelectTest', 
            'スケッチ拘束を選択して!')

        # Extension Method
        register_SelectionCommandInput_ExtensionMethod()

        # Addition by FilterT list
        selSktCon.addFilterT([
            'SketchAngularDimension',
            'SketchConcentricCircleDimension',
            'SketchDiameterDimension',
            'SketchLinearDimension',
            'SketchEllipseMajorRadiusDimension',
            'SketchEllipseMinorRadiusDimension'])

        # FilterT string addition
        selSktCon.addFilterT(
            'SketchOffsetDimension,SketchRadialDimension,hoge')
        
        # Partial deletion of FilterT
        selSktCon.removeFilterT('hoge')

class PreSelectHandler(adsk.core.SelectionEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            eventArgs = adsk.core.SelectionEventArgs.cast(args)
            selSktCon :adsk.core.SelectionCommandInput = eventArgs.firingEvent.activeInput
            try:
                preType :str = eventArgs.selection.entity.objectType.split('::')[-1]
                if not preType in selSktCon.getFilterT():
                    eventArgs.isSelectable = False
                    return
                eventArgs.isSelectable = True
            except:
                eventArgs.isSelectable = False
                
        except:
            ao = AppObjects()
            ao.ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

# -- SelectionCommandInput Extension Method --
_filterT = {}

def register_SelectionCommandInput_ExtensionMethod():
    selCmdIput = adsk.core.SelectionCommandInput

    selCmdIput.addFilterT = addFilterT
    selCmdIput.getFilterT = getFilterT
    selCmdIput.clearFilterT = clearFilterT
    selCmdIput.removeFilterT = removeFilterT

def addFilterT(self, filters):
    fType = type(filters)
    fs = []
    if fType is str:
        fs =  list(filters.split(','))
    elif fType is list:
        fs = filters
    else:
        print('filters type errer')
        return fs

    global _filterT
    if self.id in _filterT:
        tmp = _filterT[self.id]
        tmp.extend(fs)
        _filterT[self.id] = list(set(tmp))
    else:

        _filterT[self.id] = fs

def getFilterT(self):
    global _filterT
    if not self.id in _filterT:
        return []
    
    return _filterT[self.id]

def clearFilterT(self):
    global _filterT
    if self.id in _filterT:
        _filterT[self.id] = []

def removeFilterT(self, filter):
    global _filterT
    if not self.id in _filterT:
        return

    _filterT[self.id].remove(filter)

ほとんどゴッゾリ削除して、コピペしただけに近いです。
試すまで分からなかったのが、「PreSelectHandler」クラスを記載する位置と
「handlers」変数(リスト)の位置です。

pythonの場合、クラス内にクラスを作成する事が可能(理解しがたい)な
様ですが、単純にクラスを作成しても大丈夫でした。
よく出てくる「handlers」ですが、正直な所役割が分かっていないのですが
恐らくガベージ コレクションで回収されるのを避ける(ハンドラを維持しておく)
だけの為の存在だと思っています。(違ったら教えてください)


続いてアドインのエントリーポイントとなる「Fusion360AddinSkeleton.py」は
不要部分を削除し以下のように修正。

from .OreCommand import OreCommand

commands = []
command_definitions = []

cmd = {
    'cmd_name': 'Ore Command',
    'cmd_description': '俺コマンド',
    'cmd_id': 'ore',
    'cmd_resources': '',
    'workspace': 'FusionSolidEnvironment',
    'toolbar_panel_id': 'SolidScriptsAddinsPanel',
    'class': OreCommand
}
command_definitions.append(cmd)

debug = False

# Don't change anything below here:
for cmd_def in command_definitions:
    command = cmd_def['class'](cmd_def, debug)
    commands.append(command)


def run(context):
    for run_command in commands:
        run_command.on_run()


def stop(context):
    for stop_command in commands:
        stop_command.on_stop()

これ無事、Selection Filtersのバグで機能していなかった
スケッチ拘束のみが選択出来るようになりました。
こんな事だったのか。


この方が、少ないコードでギブコン'19に出したやつの続きが
実現出来そうです。ほぼコードは書き直しなんですが。

俺コマンドを作る2

こちらの続きです。
俺コマンドを作る1 - C#ATIA


忘れていましたが、実行するとこんな感じです。
f:id:kandennti:20200207094247p:plain
何か1個を選択するだけです。フィルターを指定しないと基本的に何でも
選択出来る事に、昨年気が付きました。


さて、コード的な部分です。こちらのグローバルな変数ですが、

# 俺コマンド用情報
_cmdInfo = ['cmdTest','俺コマンド','偉そうにしているが何も出来ない']

# SelectionCommandInput用情報
_selInfo = ['dlgSel','さぁ選べ!!','何もしないから']

コマンド自体とダイアログの選択を作る際の最低必要なパラメータです。
Fusion 360 Help
Fusion 360 Help
結構あちこちで必要になる事が多いので、(仕方なく)グローバルなものに
してます。

# 俺コマンドを追加するタブのID
_tabId = 'SolidTab'

# 俺コマンドを追加するパネルのID
_panelId = 'InspectPanel'

こちらは、俺コマンドを呼び出すためのボタンを作り出す場所に関するIDです。
f:id:kandennti:20200207094357p:plain
・緑:adsk.core.ToolbarTab
・赤:adsk.core.ToolbarPanel
・青:adsk.core.ToolbarControl
と言う名称のオブジェクトの様で、この順番でIDを探します。
”このIDをどうやって知るの?” と言うことになりますが、
こちらのスクリプトを使って調べます。
Fusion 360 Help

但し、現在はエラーになるはずなので、こちらに修正したものを置いておきました。
APIフォーラムでもエラーになる とチョイチョイ投げられてます)
Help記載のAPIサンプルコード(python)のエラー - Autodesk Community

某サイトではFusion360で利用出来るコマンド一覧としてこのスクリプト
紹介されていましたが、本来の目的はID取得の為だろうと思われます。

"それだけの為にスクリプト作るのメンドイ" と言う方はこちらにUpして
くれている方がいます。
GitHub - NicoSchlueter/Fusion360Templates: Script & Add-In Templates for Fusion360
"toolbarPanelNames.txt"と言うファイルがパネル名リストです。



細々したことはコメントを記載した通りなのですが、全体的な感じとしては
・CommandDefinitionを作る
 ↓
・ボタンを作るためのToolbarPanelを探し出す
 ↓
・ToolbarControlsにCommandDefinitionを突っ込む

        # 俺コマンドをパネルに登録
        # https://help.autodesk.com/view/fusion360/ENU/?guid=GUID-1ed0cfb5-2ad4-4285-9eec-484ef19f2729
        cmdControl = controls.addCommand(cmdDef)

と、なるようです。



あぁ関係ないのですが、思い出しました。
今回の俺コマンドはアドインとしましたが、公開されているコードが
アドインか? スクリプトか? を記載していないものが多いです。
・・・helpのサンプルコードですら。

コードをコピペしてくる際に逆だ動かないので、困るのですよね。
基本的な処理はどちらも変わらないのですが、俺コマンドの保持の仕方が
違うのだろうと思います。(アドインは俺コマンド定義がメモリ上に残っている)

pythonの場合の個人的な見分け方です。アドインの場合は
・"def stop(context)" がある
・Command.destroyにAddしていない(コマンド破棄イベントを使わない)

です。 正直な所よくわかっていないです・・・。