C#ATIA

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

板状に分割したい3

こちらの続きです。
板状に分割したい2 - C#ATIA

もうちょっと取り組みました。

こんな感じで、完全中空では無く一部開放している形状でも
対応出来るようにしました。
・・・ん~完全では無く、エラーになるものがあるのですが、
スクリプト自体は途中で止まらないようにはしています。

# Fusion360API Python script

import traceback
import adsk.fusion
import adsk.core


def run(context):
    ui = adsk.core.UserInterface.cast(None)
    try:
        app: adsk.core.Application = adsk.core.Application.get()
        ui = app.userInterface

        msg: str = 'ボディを選択してください'
        selFilter: str = 'Bodies'
        sel: adsk.core.Selection = selectEnt(msg, selFilter)
        if not sel:
            return

        targetBody: adsk.fusion.BRepBody = sel.entity

        execDivided(targetBody)

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

def execDivided(
    body: adsk.fusion.BRepBody) -> list:

    comp: adsk.fusion.Component = body.parentComponent

    # ******
    def getVector(
        geo: adsk.core.Surface,
        point: adsk.core.Point3D) -> adsk.core.Vector3D:

        if hasattr(geo, 'normal'):
            return geo.normal

        eva: adsk.core.SurfaceEvaluator = geo.evaluator
        _, vec = eva.getNormalAtPoint(point)

        return vec


    def getPairFaces(shell: adsk.fusion.BRepShell):
        registeredList = [] # 組み合わせ済み
        pairFaces =[]
        hitPoints: adsk.core.ObjectCollection = adsk.core.ObjectCollection.create()
        face: adsk.fusion.BRepFace
        for face in shell.faces:

            # 既に組み合わせ済みか?
            if face.entityToken in registeredList:
                continue

            pnt: adsk.core.Point3D = face.pointOnFace
            geo: adsk.core.Plane = face.geometry
            vec: adsk.core.Vector3D = getVector(geo, pnt)
            revVec: adsk.core.Vector3D = vec.copy()
            revVec.scaleBy(-1)
            vecs = [
                revVec,
                vec,
            ]

            # 候補の面取得
            tempFaces = []
            for vec in vecs:
                hitPoints.clear()
                res = comp.findBRepUsingRay(
                    pnt,
                    vec,
                    adsk.fusion.BRepEntityTypes.BRepFaceEntityType,
                    -1.0,
                    True,
                    hitPoints
                )

                if res.count < 1:
                    continue

                # 面と距離 - 向きが平行出ないものは除外
                tempFaces.extend(
                    [(f, pnt.distanceTo(p)) for f, p in zip(res, hitPoints) 
                        if vec.isParallelTo(getVector(f.geometry, p))]
                )

            if len(tempFaces) < 1:
                continue

            # 近いものが組み合わせ相手 同じボディか?ってチェック入れるべき?
            nearFace: adsk.fusion.BRepFace = min(tempFaces, key=lambda x: x[1])[0]

            if nearFace.entityToken in registeredList:
                continue

            pairFaces.append(
                (
                    face,
                    nearFace
                )
            )

            # 登録
            registeredList.extend(
                [
                    face.entityToken,
                    nearFace.entityToken
                ]
            )

        return pairFaces


    def isAllPlanarFace(body: adsk.fusion.BRepBody) -> bool:
        planeType = adsk.core.Plane.classType()
        if all([f.geometry.classType() == planeType for f in body.faces]):
            return True

        return False
    # *******
    # 全て平面かチェック
    if not isAllPlanarFace(body):
        return

    # 完全な中空形状チェック
    # if not body.shells.count == 2:
    #     return

    # 外側 これ要らないかも・・・
    outer: adsk.fusion.BRepShell = max(body.shells, key=lambda x: x.area)

    # 外内面の組み合わせ
    pairFaces = getPairFaces(outer)

    # LoftFeatures
    loftFeats: adsk.fusion.LoftFeatures = comp.features.loftFeatures

    # 外内面でロフト
    bodies = []
    for faces in pairFaces:
        loftFeatIpt: adsk.fusion.LoftFeatureInput = loftFeats.createInput(
            # adsk.fusion.FeatureOperations.NewBodyFeatureOperation
            adsk.fusion.FeatureOperations.NewComponentFeatureOperation
        )
        loftFeatIpt.isSolid = True
        loftFeatIpt.isClosed = False

        loftSections: adsk.fusion.LoftSections = loftFeatIpt.loftSections
        [loftSections.add(f) for f in faces]

        try:
            # エラーが出るので苦肉の策・・・
            loftFeat: adsk.fusion.LoftFeature = loftFeats.add(loftFeatIpt)

            bodies.append(loftFeat.bodies[0])
        except:
            adsk.core.Application.get().log(
                'Failed:\n{}'.format(traceback.format_exc())
            )

    return bodies

def selectEnt(
        msg: str,
        filterStr: str) -> adsk.core.Selection:

    try:
        app: adsk.core.Application = adsk.core.Application.get()
        ui: adsk.core.UserInterface = app.userInterface
        sel = ui.selectEntity(msg, filterStr)
        return sel
    except:
        return None


"全て平らな面" と言う条件を無くしたいと思い、全て曲面
(フォームで作成しシェルしたボディ)も試しました。

頑張ってそれっぽく出来上がるものもあるのですが、

今年のF1のサイド・ポンツーンよりえぐれてそうな
ムリムリな形状も出来ます。

なので諦めました。