C#ATIA

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

フィレットの元のエッジを探せ!!5

こちらの続きです。
フィレットの元のエッジを探せ!!4 - C#ATIA

前回は単調にentityTokenを文字として出力しましたが、
比較が面倒な為、画面上に色付きのエッジとして表示させる
ことにしました。

# Fusion360API Python script

import traceback
import adsk.fusion
import adsk.core

_app: adsk.core.Application = None
_ui: adsk.core.UserInterface = None
_handlers = []
_selIpt: adsk.core.SelectionCommandInput = None
_cmdInfo = {
    'id': 'KANTOKU_EntityTokenDump',
    'name': 'Entity TokenDump',
    'tooltip': 'Entity TokenDump',
}

class MyCommandCreatedHandler(adsk.core.CommandCreatedEventHandler):
    def __init__(self):
        super().__init__()

    def notify(self, args: adsk.core.CommandCreatedEventArgs):
        try:
            global _handlers
            cmd: adsk.core.Command = adsk.core.Command.cast(args.command)
            cmd.isOKButtonVisible = False

            inputs: adsk.core.CommandInputs = cmd.commandInputs

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

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

            global _selIpt
            _selIpt = inputs.addSelectionInput(
                'selIptId',
                'Select Feature',
                ''
            )
            _selIpt.addSelectionFilter(
                adsk.core.SelectionCommandInput.Features
            )

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


class MyExecutePreviewHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args: adsk.core.CommandEventArgs):
        global _selIpt
        feat: adsk.fusion.Feature = _selIpt.selection(0).entity
        showTokenEdges(feat)

                
def showTokenEdges(feat: adsk.fusion.Feature):
    app: adsk.core.Application = adsk.core.Application.get()
    des: adsk.fusion.Design = app.activeProduct

    def getAllEdges(bodies: adsk.fusion.BRepBodies) -> list:
        bodyLst = []
        try:
            for body in bodies:
                [bodyLst.append(e) for e in body.edges]
        except:
            pass

        return bodyLst

    def getEdgeTokenSet(bodies: adsk.fusion.BRepBodies) -> set:
        return set([e.entityToken for e in getAllEdges(bodies)])

    def drawCG(edges, color):
        root: adsk.fusion.Component = des.rootComponent
        tmpMgr: adsk.fusion.TemporaryBRepManager = adsk.fusion.TemporaryBRepManager.get()
        clones = [tmpMgr.copy(e) for e in edges]

        cgGroup: adsk.fusion.CustomGraphicsGroup = root.customGraphicsGroups.add()
        for body in clones:
            try:
                cgCurve: adsk.fusion.CustomGraphicsCurve= cgGroup.addCurve(body.edges[0].geometry)
                cgCurve.weight = 3.0
                cgCurve.color = color
            except:
                pass

        adsk.doEvents()
        app.activeViewport.refresh()


    # *****
    timeline: adsk.fusion.Timeline = des.timeline
    timeObj: adsk.fusion.TimelineObject = feat.timelineObject

    timeObj.rollTo(True)
    previousTimeObj: adsk.fusion.TimelineObject = timeline.item(
        timeline.markerPosition - 1
    )
    previousFeat: adsk.fusion.Feature = previousTimeObj.entity
    
    if not hasattr(previousFeat, 'bodies'):
        return
    previousEdgeTokens = getEdgeTokenSet(previousFeat.bodies)


    timeObj.rollTo(False)
    if not hasattr(feat, 'bodies'):
        return

    intersection = []
    difference = []
    edges = getAllEdges(feat.bodies)
    for edge in edges:
        if edge.entityToken in previousEdgeTokens:
            intersection.append(edge)
        else:
            difference.append(edge)

    drawCG(
        intersection,
        adsk.fusion.CustomGraphicsSolidColorEffect.create(
            adsk.core.Color.create(0, 0, 255, 255)
        )
    )

    drawCG(
        difference,
        adsk.fusion.CustomGraphicsSolidColorEffect.create(
            adsk.core.Color.create(255, 0, 0, 255)
        )
    )

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

    def notify(self, args: adsk.core.CommandEventArgs):
        adsk.terminate()


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

スクリプトを実行してタイムラインのフィーチャを選択すると、
もう一つ手前のタイムラインのフィーチャのエッジと
entityTokenを比較した結果を表示します。
ん~言葉じゃ難しい。

青色はentityTokenが変更されていないエッジで、
赤色はentityTokenが変更されたエッジです。


具体的に単純な例を示すと

・スケッチ->押し出し->フィレット1
・フィレット2
・フィレット3
の順で作成した場合に先程のフィレット2を選択した場合は
この様な表示になります。

黄色のエッジは画面上では変更が無いものの、entityTokenは
変更されています。
まぁこれはこれで、"Fusion360の仕様" として受け入れる
しかない と思っています。

ここで、タイムラインのフィレット2とフィレット3の
順番を入れ替え、今度はフィレット3をスクリプト
選択した結果です。

黄色のエッジは画面上では変更が無く、entityTokenも
変更されてません。何故・・・。
念の為、タイムラインの入れ替えでは無く、新規にあの順番で
フィレットを付けた場合でも同様の結果となります。


モデリングを行った方法?順番?によって得られる結果が
異なるようでは、何が正しいものなのかが分からなく、
心底行き詰まり感を感じます。

推測ですが、エッジのentityTokenについては、今の所こんな
解釈でいます。
・エッジのentityTokenについては、面のentityTokenに依存している。
・共有しているエッジの場合は、両側の面のエッジのどちらかの
 entityTokenとなっている。(恐らくエッジ自体が)
・両側の面のどちらかのエッジが採用されるか?のルールが
 あるが、わからない。
例えば、フィレット1,2,3の時は

黄色星の面がピンク色エッジを持っていて、フィレットを付けた際に
黄色星の面が変更される為、新たな面が作成されentityTokenが
変更され、
フィレット1,3,2の時は

黄色星の面がエッジを持っているのだろうと思っています。

仮にこれが正しい解釈だとしても、依存を見つける事には
役に立たないです。 困った。