C#ATIA

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

極平面

ボディと方向を指定した際、方向に対しての最大位置・最小位置に
平面を作るスクリプトを作成しました。

# Author-kantoku
# Description-極平面
# Fusion360API Python script

import traceback
import adsk.fusion
import adsk.core

_app: adsk.core.Application = None
_ui: adsk.core.UserInterface = None

_handlers = []

_cmdInfo = {
    'id': 'polar_plane',
    'name': '極平面',
    'tooltip': '指定方向に極平面作成',
}

_bodyIpt: adsk.core.SelectionCommandInput = None
_directionIpt: adsk.core.SelectionCommandInput = None

def run(context):
    try:
        global _app, _ui
        _app = adsk.core.Application.get()
        _ui = _app.userInterface

        global _cmdInfo
        cmdDef: adsk.core.CommandDefinition = _ui.commandDefinitions.itemById(
            _cmdInfo['id']
        )

        if not cmdDef:
            cmdDef = _ui.commandDefinitions.addButtonDefinition(
                _cmdInfo['id'],
                _cmdInfo['name'],
                _cmdInfo['tooltip']
            )

        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()))


def getNormalVec(
    entity) -> adsk.core.Vector3D:

    def getMat(
        entity) -> adsk.core.Matrix3D:

        occ: adsk.fusion.Occurrence = entity.assemblyContext

        if occ:
            return occ.transform2

    # *****
    mat: adsk.core.Matrix3D = getMat(entity)

    geo = entity.geometry
    if mat:
        geo.transformBy(mat)

    if hasattr(entity, 'worldGeometry'):
        geo = entity.worldGeometry

    if hasattr(geo, 'normal'):
        return geo.normal
    elif hasattr(geo, 'direction'):
        return geo.direction
    elif hasattr(geo, 'asInfiniteLine'):
        inf: adsk.core.InfiniteLine3D = geo.asInfiniteLine()
        return inf.direction

    raise Exception


def initPolarPlanes(
    body: adsk.fusion.BRepBody,
    direction: adsk.core.Vector3D) -> list:

    def initConstructionPlane(
        plane: adsk.core.Plane,
        constPlanes: adsk.fusion.ConstructionPlanes) -> adsk.fusion.ConstructionPlane:

        plnIpt: adsk.fusion.ConstructionPlaneInput = constPlanes.createInput()
        plnIpt.setByPlane(plane)

        return constPlanes.add(plnIpt)

    def initVerticalPlanes(
        bBox: adsk.core.OrientedBoundingBox3D) -> list:

        lengthLst = [
            bBox.height * 0.5,
            bBox.height * -0.5
        ]

        planes = []
        for l in lengthLst:
            v: adsk.core.Vector3D = bBox.heightDirection.copy()
            v.scaleBy(l)

            p: adsk.core.Point3D = bBox.centerPoint.copy()
            p.translateBy(v)

            planes.append(
                adsk.core.Plane.create(p, bBox.heightDirection)
            )

        return planes

    def getBoundingBox(
        body: adsk.fusion.BRepBody,
        direction: adsk.core.Vector3D) -> adsk.core.OrientedBoundingBox3D:

        plane = adsk.core.Plane = adsk.core.Plane.create(
            adsk.core.Point3D.create(0,0,0),
            direction
        )

        app: adsk.core.Application = adsk.core.Application.get()
        measMgr: adsk.core.MeasureManager = app.measureManager
        return measMgr.getOrientedBoundingBox(
            body,
            plane.vDirection,
            plane.uDirection
        )

    # ****************

    # get OrientedBoundingBox
    bBox: adsk.core.OrientedBoundingBox3D = getBoundingBox(
        body,
        direction
    )

    # get Vertical Planes
    planes = initVerticalPlanes(bBox)

    # init Construction Planes
    app: adsk.core.Application = adsk.core.Application.get()
    des: adsk.fusion.Design = app.activeProduct

    comp: adsk.fusion.Component = body.parentComponent

    baseFeat: adsk.fusion.BaseFeature = None
    if des.designType == adsk.fusion.DesignTypes.ParametricDesignType:
        baseFeat = comp.features.baseFeatures.add()

    constPlanes: adsk.fusion.ConstructionPlanes = comp.constructionPlanes

    resPlanes = []

    if baseFeat:
        baseFeat.startEdit()
        for pln in planes:
            resPlanes.append(initConstructionPlane(pln, constPlanes))
        baseFeat.finishEdit()
    else:
        for pln in planes:
            resPlanes.append(initConstructionPlane(pln, constPlanes))

    return resPlanes


class MyInputChangedHandler(adsk.core.InputChangedEventHandler):
    def __init__(self):
        super().__init__()

    def notify(self, args: adsk.core.InputChangedEventArgs):
        # adsk.core.Application.get().log(args.firingEvent.name)

        if args.input.classType() != adsk.core.SelectionCommandInput.classType():
            return

        global _bodyIpt, _directionIpt

        if _bodyIpt.selectionCount < 1:
            _bodyIpt.hasFocus = True
            return

        if _directionIpt.selectionCount < 1:
            _directionIpt.hasFocus = True


class MyExecutePreviewHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args: adsk.core.CommandEventArgs):
        # adsk.core.Application.get().log(args.firingEvent.name)

        global _bodyIpt, _directionIpt

        initPolarPlanes(
            _bodyIpt.selection(0).entity,
            getNormalVec(_directionIpt.selection(0).entity)
        )

        args.isValidResult = True


class MyPreSelectHandler(adsk.core.SelectionEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args: adsk.core.SelectionEventArgs):
        # adsk.core.Application.get().log(args.firingEvent.name)

        selIpt: adsk.core.SelectionCommandInput = args.activeInput

        if selIpt.selectionCount > 0:
            args.isSelectable = False


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)

        global _bodyIpt, _directionIpt

        if _bodyIpt.selectionCount < 1 or _directionIpt.selectionCount < 1:
            args.areInputsValid = False


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)

            # event
            onDestroy = MyCommandDestroyHandler()
            cmd.destroy.add(onDestroy)
            _handlers.append(onDestroy)

            onInputChanged = MyInputChangedHandler()
            cmd.inputChanged.add(onInputChanged)
            _handlers.append(onInputChanged)

            onExecutePreview = MyExecutePreviewHandler()
            cmd.executePreview.add(onExecutePreview)
            _handlers.append(onExecutePreview)

            onPreSelect = MyPreSelectHandler()
            cmd.preSelect.add(onPreSelect)
            _handlers.append(onPreSelect)

            onValidateInputs = MyValidateInputsHandler()
            cmd.validateInputs.add(onValidateInputs)
            _handlers.append(onValidateInputs)


            # inputs
            inputs: adsk.core.CommandInputs = cmd.commandInputs

            global _bodyIpt, _directionIpt
            _bodyIpt = inputs.addSelectionInput(
                'bodyIpt',
                'ボディ',
                'ボディを選択して下さい'
            )
            _bodyIpt.addSelectionFilter('Bodies')
            _bodyIpt.setSelectionLimits(0)

            _directionIpt = inputs.addSelectionInput(
                'directionIpt',
                '方向',
                '方向となる要素を選択して下さい'
            )
            _directionIpt.addSelectionFilter('SketchLines')
            _directionIpt.addSelectionFilter('ConstructionLines')
            _directionIpt.addSelectionFilter('ConstructionPlanes')
            _directionIpt.addSelectionFilter('LinearEdges')
            _directionIpt.addSelectionFilter('PlanarFaces')
            _directionIpt.setSelectionLimits(0)

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


class MyCommandDestroyHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()

    def notify(self, args: adsk.core.CommandEventArgs):
        # adsk.core.Application.get().log(args.firingEvent.name)

        adsk.terminate()


ボディ:ソリッド・サーフェス等のボディ(メッシュはNG)
方向:スケッチの直線、構築軸、構築平面、ボディのまっすぐなエッジ、
   ボディの平らな面 等
を選択すると、最大位置・最小位置に平面をプレビューします
(相当見えにくい・・・)ので、OKボタンで作成されます。

上記のコードをコピーしこちらの "素のコード" の方法で作成した
ファイルにペーストし実行して頂くと、利用出来ると思います。
Fusion360のスクリプト/アドインの登録 - C#ATIA