こちらの続きです。
オフセット面の作成場所 - C#ATIA
前回の最後に記載した
”コンポーネントからオカレンスをどうやったら取得できるのか?”
のテストです。
ややこしいのですが、こんな状態のデータでテストします。
青部分がルートコンポーネント
赤Bodyを最初に選択してテスト(root - コンポーネント1:1 のBody)
緑Bodyを後で選択してテスト(root - コンポ1:1 - コンポ2:1 - コンポ3:1 のBody)
このようなコードを用意しました。
#FusionAPI_python test_offset #Author-kantoku #Description-オフセット面の作成 import adsk.core, adsk.fusion, traceback def run(context): ui = None try: app = adsk.core.Application.get() ui = app.userInterface #選択 sel = Sel('Select Base Body','SolidBodies') if sel is None: return #選択したボディ bd = sel.entity #ボディからコンポーネント comp = bd.parentComponent print('--start--') print('// 選択した ボディ名 - コンポ名 //') print('{}-{}'.format(bd.name,comp.name)) #作業中のデザイン(作業中のファイルみたいなもの) des = adsk.fusion.Design.cast(app.activeProduct) #ルートコンポーネント(全体のコンポーネント) root = des.rootComponent #コンポーネントのメソッド・プロパティ comps = root.allOccurrencesByComponent(comp) print('// allOccurrencesByComponent //') [DumpOccInfo(o) for o in comps] comps = root.occurrencesByComponent(comp) print('// occurrencesByComponent //') [DumpOccInfo(o) for o in comps] comps = comp.occurrences print('// occurrences //') [DumpOccInfo(o) for o in comps] print('--done--') except: if ui: ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) #オカレンス情報 def DumpOccInfo(occ): print('--occ info --\nocc name : {}\n子Occ数 : {}\nコンポ名 : {}\n' .format(occ.name,len(occ.childOccurrences),occ.component.name)) #選択 def Sel(msg, selFilter): app = adsk.core.Application.get() ui = app.userInterface try: return ui.selectEntity(msg, selFilter) except: return None
コンポーネントクラスにはオカレンスが関連しそうなメソッド・プロパティが
3個ありました。
・allOccurrencesByComponent(メソッド)
・occurrencesByComponent(メソッド)
・occurrences(プロパティ)
正直なところ、APIのHelp読んでも意味がわからないのでテストした
ってことです。 通常 "プロパティでしょ" とは思っています。
赤Bodyを選択した結果はこちら
--start-- // 選択した ボディ名 - コンポ名 // Body1-コンポーネント1 // allOccurrencesByComponent // --occ info -- occ name : コンポーネント1:1 子Occ数 : 2 コンポ名 : コンポーネント1 // occurrencesByComponent // --occ info -- occ name : コンポーネント1:1 子Occ数 : 2 コンポ名 : コンポーネント1 // occurrences // --occ info -- occ name : コンポーネント2:1 子Occ数 : 1 コンポ名 : コンポーネント2 --occ info -- occ name : コンポーネント4:1 子Occ数 : 0 コンポ名 : コンポーネント4 --done--
赤Bodyを選択した際に欲しいのは、"コンポーネント1:1" です。
occurrences(プロパティ)で得られるのは、そのコンポーネントに
ぶら下がっているコンポーネント(子コンポーネント)です。
"コンポーネント3:1" が得られていないので、孫以下は見ていないです。
※ならば、ChildrenOccurrenceのような名称の方がわかりやすい!!
緑Bodyを選択した結果はこちら
--start-- // 選択した ボディ名 - コンポ名 // Body1-コンポーネント3 // allOccurrencesByComponent // --occ info -- occ name : コンポーネント3:1 子Occ数 : 0 コンポ名 : コンポーネント3 // occurrencesByComponent // // occurrences // --done--
occurrences(プロパティ)については、子供のオカレンスが無い為
出力無しは納得です。
occurrencesByComponent(メソッド)の出力無しについては
ルートコンポーネントから見て、緑Bodyの入っているオカレンスが
ひ孫の位置にあるため得られないため、出力無しとなるのだろうと
思います。(あくまで対象は子供のオカレンスのみ)
allOccurrencesByComponent(メソッド)は "all" が付いている
だけあって呼び出したコンポーネント(今回はルートコンポーネント)
以下のオカレンスであれば取得できるようです。
※よく見たらallOccurrences(プロパティ)もありましたが、
動作は察しが付きますし、目的のものでも無さそうです。
で、探した限り直接コンポーネントから該当するプロパティは
無さそうな気がしています。
その為、拡張メソッド用の関数を用意し昨日のオフセットスプリクトを
修正しました。
#FusionAPI_python test_offset2 #Author-kantoku #Description-オフセット面の作成 import adsk.core, adsk.fusion, traceback def run(context): ui = None try: app = adsk.core.Application.get() ui = app.userInterface des = adsk.fusion.Design.cast(app.activeProduct) #拡張 adsk.fusion.Component.toOcc = toOccurrenc sel = Sel('Select Solid Face','SolidFaces') if sel is None: return face = sel.entity CreateZeroOffset(face) ui.messageBox('Done') except: if ui: ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) def Sel(msg, selFilter): app = adsk.core.Application.get() ui = app.userInterface try: return ui.selectEntity(msg, selFilter) except: return None def CreateZeroOffset(face): zero = adsk.core.ValueInput.createByString('0 cm') newBody = adsk.fusion.FeatureOperations.NewBodyFeatureOperation #選択された面のあるボディのコンポーネント取得 comp = face.body.parentComponent #コンポーネントのフューチャーのオフセットを取得 offsets = comp.features.offsetFeatures objs = adsk.core.ObjectCollection.create() objs.add(face) occ = comp.toOcc() if not occ is None: occ.activate() offsets.add(offsets.createInput(objs, zero, newBody)) #adsk.fusion.Component 拡張メソッド def toOccurrenc(self): root = self.parentDesign.rootComponent if self == root: return None occs = [occ for occ in root.allOccurrencesByComponent(self) if occ.component == self] return occs[0]
意図した位置にオフセット面が作成出来るようになりました。
本来であれば実行前のコンポーネントをアクティブにして終了したいの
ですが、ルートではオカレンスが取得できない為、オフセット面を
作った状態で終了と、雑な処理になっています。
Fusion360APIの場合、コンポーネントとオカレンスは密接な関係だと
思っていますが、特にオカレンスに関してはわかりにくいのが本音です。
知っていることを含めまとめると
・ルートコンポーネントにはオカレンスが無い。
(ルート自体は固定されていて、移動等出来ない為だと思う)
・Treeに "コンポーネント" と書かれているものは実はオカレンス
nameプロパティを取得した感じだと、こんなイメージ。
名前が異なる為、「itemByName」では取得できない。
・"コンポーネント" は各コンポーネントを作業しているような状態で
ルートから見た際(移動等位置決めしている場合)オカレンスとして
扱う必要がある。
・オカレンスは重要なのにBRep~(例えばBRepBody)には、直接
オカレンスを取得する方法が無い。(と思う)
parentComponentメソッドはあるけど、parentOccurrenceは無い。
・手動の "コンポーネントのアクティブ化" はAPIの場合、
Occurrence.activate() になるようですが、ルートコンポーネントに
オカレンスが無いのでどうやれば良いのだろうか?
Helpも "コンポーネント" と説明している部分が圧倒的多数なのですが
実際はオカレンスを説明している部分もありそうな感じです。