C#ATIA

↑タイトル詐欺 主にFusion360API 偶にCATIA V5 VBA(絶賛ネタ切れ中)※記載されている内容は個人の意見であり、所属する団体等を代表する意見では御座いません・・・・よ!

外周エッジを取得する

少し前ですが、こんな感じで複数の面から構成されているボディ(サーフェス
の外周の境界の線を取得したかった際に、ちょっと迷ったのでご紹介を。

CATIA V5の場合であれば、境界コマンドで簡単に作れます。
・・・厳密に言えば、外周の境界線から線を作るだけで、境界線そのもの
じゃないのですが。
但し、Fusion360ではそれすら ズバッと行う機能が無いと思います。

Fusion360ではソリッドであろうがサーフェスだろうがボディは"BRepBody"に
なります。ドキュメントのこちらのページにガッチリ?ゴッツリ?
説明があります。
Fusion Help

"BRepLump"についての表現を簡単にすれば、"2個のソリッドが1個のボディ"に
なっている状態です。CATIA V5ではこの状態を作る事が出来るのですが、
Fusion360の場合はGUIでこれを作ろうとしても強制的に1個のソリッドで1個のボディ
の状態になります。
(スケッチで離れた2個の円を描いて、1回の押し出して2個の円を選択すると、2個の
ボディが出来上がります)
結論からしてこれは無視です。

"BRepShell"はサーフェス的なイメージです。説明書きにあるように、中空のボディの
場合は、外側の面と内側の面が離れているにも関わらず1個のボディとして成立
しますね。ものづくりな視点で考えると "作れない形状じゃん" と思ったのですが、
3Dプリンタであれば作れそうな気もします。

"BRepFace"は面そのものです。そう1枚の面です。

"BRepLoop"は面の境界です。これは1枚の面(BRepFace)の境界であって、"BRepShell"
(複数の面がくっ付いた状態)の境界では無いです。
"BRepShell"にloopsプロパティがあれば目的が簡単に達成出来そうだと思ったの
ですが、残念な事にありませんでした。
Fusion Help

そこで"どうする?"となるのですが、結論から書くと"BRepCoEdge"を利用します。
あのリンク先の"BRepXXX"は"BRepCoEdge"以外はジオメトリ(幾何学)的な
要素なのですが"BRepCoEdge"のみトポロジー(位相幾何学)的な要素です。
上手く説明できていないかも知れませんが、

ジオメトリー:座標値や線の長さ等の形状的な情報
トポロジー:隣の面はどれ?このエッジを利用している面はどれ?等の関係性の情報

です・・・多分。

今回の場合はエッジについて注目するのですが、"BRepCoEdge"は
ハーフエッジデータ構造(個人的にはハーフエッジ構造と覚えていました)
を採用しています。

ハーフエッジデータ構造の説明書きを探した所こちらを見つけました。
ハーフエッジデータ構造を理解する #データ構造 - Qiita
難しいので理解できないですね・・・。

但し、分かっている事は赤のエッジの場合は片方のハーフエッジの反対側にも
ハーフエッジが存在しているのですが、緑のエッジは片方のハーフエッジ
反対側にはハーフエッジが無いと言う事です。

これさえ理解していれば、外周のエッジは"BRepEdge"のcoEdgesプロパティ
が1個だと言う事が分かります。
Fusion Help

そこでこんな感じにスクリプトを作りました。

# Fusion360API Python script

import traceback
import adsk.core as core
import adsk.fusion as fusion

def run(context):
    ui: core.UserInterface = None
    try:
        app: core.Application = core.Application.get()
        ui = app.userInterface
        des: fusion.Design = app.activeProduct
        root: fusion.Component = des.rootComponent

        body: fusion.BRepBody = root.bRepBodies[0]
        print(f"{body.name}:{body.faces.count}")

        outerEdges = [edge for edge in body.edges if edge.coEdges.count < 2]
        select_entities(outerEdges)

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


def select_entities(entities: list):
    app: core.Application = core.Application.get()
    sels: core.Selections = app.userInterface.activeSelections

    sels.clear()
    [sels.add(x) for x in entities]

実際に実行した結果はこちらです。(左実行前 右実行後)

本当は数日前にもうちょっと詳しく書こうと思っていたのですが、
睡魔に負けてしまい・・・。