@loverinlen さん, @kandennti さん
とりあえずテストで作ってみました.
普通のシェルコマンドの要領で,対象となるボディと厚みを入力すれば分割されたボディが生成されます.
(なので,シェルを実行する前の状態のボディの状態でプログラムを実行してください.)
#Author-
#Description-
import adsk.core, adsk.fusion, adsk.cam, traceback
_app: adsk.core.Application = None
_ui: adsk.core.UserInterface = None
_handlers = []
_selIpt: adsk.core.SelectionCommandInput = None
_tabIpt: adsk.core.SelectionCommandInput = None
_thickness = 0
def run(context):
ui = None
try:
global _app, _ui
_app = adsk.core.Application.get()
_ui = _app.userInterface
cmdDef: adsk.core.CommandDefinition = _ui.commandDefinitions.itemById(
'Shell_and_Loft'
)
if not cmdDef:
cmdDef = _ui.commandDefinitions.addButtonDefinition(
'Shell_and_Loft',
'Shell_and_Loft',
'Shell_and_Loft'
)
global _handlers
onCommandCreated = MyCommandCreatedHandler()
cmdDef.commandCreated.add(onCommandCreated)
_handlers.append(onCommandCreated)
cmdDef.execute()
adsk.autoTerminate(False)
except:
if _ui:
_ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
class MyCommandCreatedHandler(adsk.core.CommandCreatedEventHandler):
def __init__(self):
super().__init__()
def notify(self, args: adsk.core.CommandCreatedEventArgs):
adsk.core.Application.get().log(args.firingEvent.name)
try:
global _handlers
cmd: adsk.core.Command = adsk.core.Command.cast(args.command)
# OKボタンの表示を変更
cmd.okButtonText = 'Create'
# イベント登録
onDestroy = MyCommandDestroyHandler()
cmd.destroy.add(onDestroy)
_handlers.append(onDestroy)
# 実行ボタンのコントロールイベント登録
onValidateInputs = MyValidateInputsHandler()
cmd.validateInputs.add(onValidateInputs)
_handlers.append(onValidateInputs)
# OKボタンを押した際のイベント
onExecute = MyExecuteHandler()
cmd.execute.add(onExecute)
_handlers.append(onExecute)
# 入力窓
inputs: adsk.core.CommandInputs = cmd.commandInputs
global _selIpt, _tabIpt, _thickness
_selIpt = inputs.addSelectionInput(
'_selIpt1',
'SolidBody',
'SolidBody'
)
# フィルターを設定する
_selIpt.addSelectionFilter('Bodies')
# リミットの設定
_selIpt.setSelectionLimits(1, 1)
# Create a tab input.
_thickness = inputs.addValueInput(
'Thickness',
'Thickness',
'mm',
adsk.core.ValueInput.createByReal(0.0))
# Connect to the command destroyed event.
onDestroy = MyCommandDestroyHandler()
cmd.destroy.add(onDestroy)
_handlers.append(onDestroy)
except:
_ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
# OKボタンのコントロール
class MyValidateInputsHandler(adsk.core.ValidateInputsEventHandler):
def __init__(self):
super().__init__()
def notify(self, args: adsk.core.ValidateInputsEventArgs):
adsk.core.Application.get().log(args.firingEvent.name)
# 1ボディ,厚みとして正の値が入力されているときに実行可能
global _selIpt, _thickness
if not ((_selIpt.selectionCount == 1) and ((_thickness.value) > 0)):
args.areInputsValid = False
return
# OKボタン選択後
class MyExecuteHandler(adsk.core.CommandEventHandler):
def __init__(self):
super().__init__()
def notify(self, args: adsk.core.CommandEventArgs):
adsk.core.Application.get().log(args.firingEvent.name)
# ダイアログ上のSelectionCommandInput
global _thickness
product = _app.activeProduct
design = adsk.fusion.Design.cast(product)
rootComp = design.rootComponent
features = rootComp.features
# シェル前に既存の面情報を取得
body_info = _app.activeProduct.allComponents[0].bRepBodies[0]
face_info = body_info.faces
face_ID_out = []
face_vDirec_out = []
for i in range(face_info.count):
face_ID_out.append(face_info[i].tempId)
face_vDirec_out.append(face_info[i].geometry.vDirection)
# シェルの実行
entities1 = adsk.core.ObjectCollection.create()
entities1.add(body_info)
shellFeats = features.shellFeatures
isTangentChain = False
shellFeatureInput = shellFeats.createInput(entities1, isTangentChain)
thickness = adsk.core.ValueInput.createByReal(_thickness.value)
shellFeatureInput.insideThickness = thickness
shellFeats.add(shellFeatureInput)
# シェルにより生成した新規の面情報を取得
face_ID_in = []
face_vDirec_in = []
for i in range(face_info.count):
ID = face_info[i].tempId
if not ID in face_ID_out:
face_ID_in.append(ID)
face_vDirec_in.append(face_info[i].geometry.vDirection)
# 探索方法:シェルにより生成される面に振られるIDと既存のIDには関係性がありそうなのでそれを利用
for i in range(len(face_ID_out)):
for j in range(face_info.count):
if face_ID_out[i] == face_info[j].tempId:
profile1 = face_info[j]
elif face_ID_in[i] == face_info[j].tempId:
profile2 = face_info[j]
loftFeats = rootComp.features.loftFeatures
loftInput = loftFeats.createInput(adsk.fusion.FeatureOperations.NewBodyFeatureOperation)
loftSectionsObj = loftInput.loftSections
loftSectionsObj.add(profile1)
loftSectionsObj.add(profile2)
loftInput.isSolid = True
loftInput.isClosed = False
loftInput.isTangentEdgesMerged = True
loftFeats.add(loftInput)
class MyCommandDestroyHandler(adsk.core.CommandEventHandler):
def __init__(self):
super().__init__()
def notify(self, args: adsk.core.CommandEventArgs):
adsk.terminate()
ただ,どうしようかな,と悩んでいる部分がありまして...
例えば以下のようにブロックの上にブロックが詰まれている状態の時
このプログラムを実行すると,特定の部分でロフトにエラーが発生します
ブロック同士のつなぎ目の部分ですね
穴が開いているプロファイルなのでロフトが失敗してしまいます.
もし,こういう形状の者は対象としない!となればいい線言ってるかな...という感じなのですがどこか悔しい感じもあったり.
進捗報告でした.
要望,質問等ございましたらご連絡ください.