C#ATIA

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

NURBS面を円筒面に変換する2

こちらの続きです。
NURBS面を円筒面に変換する1 - C#ATIA

えーまずNurbs面から円筒面にする面を探し出す必要があるのですが、
難しいです。

こちらに添付されているデータをテストデータにします。
解決済み: STEPからインポートしたデータの面構成を簡単に修正する方法が欲しい - Autodesk Community
本当はもっと色々なデータが必要なのですが、タダでさえ
迷っているので、これが処理できるようにするのが、まず
目標にしておきます。


色々悩みますが、とりあえず軸を見つけたいです。
あちらのデータ(元CATIA)はUVのどちらかが直線だったため、
比較的簡単に軸を見つけられました。
しかし、こちらのスクリプトでNURBS化したものは、
UV両方ともnurbs曲線になってしまいました。
(本気でnurbs化する事を実感)

そこで、面上にランダムな点を作成し、点の位置から
法線と曲率を取得し、点の位置を法線方向にRサイズ(曲率の逆数)
移動させた際の位置が中心軸になるのでは?と感じてます。
(言葉だけだとわかりにくいですね)

説明不足が半端じゃないのですが、こんなスクリプトを作りました。

# Fusion360API Python script

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

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]

        nurbss = get_nurbs_faces(body)
        group = group_by_faces(nurbss)

        test(group[0], False)


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


def test(faces: list, isAbs: bool):

    face: fusion.BRepFace = None
    for face in faces:

        eva: core.SurfaceEvaluator = face.evaluator

        # _, prm = eva.getParameterAtPoint(
        #     face.pointOnFace
        # )
        # _, vec, crvMax, crvMin = eva.getCurvature(prm)

        prmRange: core.BoundingBox2D = eva.parametricRange()
        prms = [
            core.Point2D.create(
                random.uniform(
                    prmRange.minPoint.x,
                    prmRange.maxPoint.x,
                ),
                random.uniform(
                    prmRange.minPoint.y,
                    prmRange.maxPoint.y,
                ),
            ) for _ in range(10)
        ]
        _, _, crvMaxs, _ = eva.getCurvatures(prms)
        _, nmls = eva.getNormalsAtParameters(prms)

        _, pnts = eva.getPointsAtParameters(prms)
        v: core.Vector3D = None
        cr: float = -10000
        p1: core.Point3D = None
        pntSets = []
        for p1, v, cr in zip(pnts, nmls, crvMaxs):
            p2: core.Point3D = p1.copy()
            r = 1/cr
            if isAbs:
                r = abs(r)
            v.normalize
            v.scaleBy(r)
            p2.translateBy(v)
            pntSets.append((p1, p2))

        dump_lines(pntSets)


def dump_lines(pntSets):
    app: core.Application = core.Application.get()
    des: fusion.Design = app.activeProduct
    root: fusion.Component = des.rootComponent

    skt: fusion.Sketch = root.sketches.add(root.xYConstructionPlane)
    sktLines: fusion.SketchLines = skt.sketchCurves.sketchLines
    [sktLines.addByTwoPoints(p1, p2) for p1, p2 in pntSets]


def group_by_faces(
    faces: list,
) -> list:

    group = []

    face: fusion.BRepFace = None
    tokens = [face.entityToken for face in faces]
    for face in faces:
        if face.entityToken not in tokens:
            continue

        tokens.remove(face.entityToken)

        tangents = col2lst(face.tangentiallyConnectedFaces)
        if len(tangents) < 1:
            continue

        [tokens.remove(f.entityToken) for f in tangents]
        tangents.append(face)

        group.append(tangents)

    return group


def get_nurbs_faces(
    body: fusion.BRepBody,
) -> list:

    return [f for f in body.faces if f.geometry.objectType == core.NurbsSurface.classType()]


def col2lst(
    col: core.ObjectCollection,
) -> list:

    return [x for x in col]

ルートコンポーネント内の最初のボディのnurbs面の組み合わせに、
ランダムな点を10個作成し、法線から曲率分移動させた点との
間に直線を作り出します。ね、説明しても無駄でしょ?

実行するとこんな感じです。

あぁ中心に向かっていません。
曲率がマイナスの値になっていた事は気が付いていたので、
ここを修正します。

        # test(group[0], False)
        test(group[0], True)


それっぽく軸の位置に集まりそうです。このデータの場合は
絶対値でOKっぽいです。

続いて、モデルを変更します。 穴では無く、軸っぽくします。

あくまで元の面を活かしたいので、結合の差を使って作りました。

同じようにスクリプトを実行すると

絶対値での場合は望む結果になりませんでした。

最初の状態に戻し試すと

上手く行きました。

結果的に、
・穴: 絶対値
・軸: そのまま
で見つけ出せそうな気はしているのですが、
本当にこれで良いのかな・・・。

穴と軸では処理を変えたい部分があるので、これで
判断して良いのかな・・・。