C#ATIA

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

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

結構頑張っているつもりなのに、今月はブログの更新が少ない・・・。

こちらの動画のスクリプトを無くしそうなので、公開しておきます。

# 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

        msg: str = 'Select'
        selFilter: str = 'Faces'

        while True:
            sel: core.Selection = selectEnt(msg, selFilter)
            if not sel:
                break

            create_simple_cylinder_face(sel.entity)

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


def create_simple_cylinder_face(
    face: fusion.BRepFace,
) -> None:

    tangens = [f for f in face.tangentiallyConnectedFaces]
    tangens.append(face)

    res = add_offset_faces(tangens, 0.001)
    if not res:
        return

    cylinder = create_cylinder(tangens)

    diff_body(face.body, cylinder)


def create_cylinder(
    faces: list,
) -> fusion.BRepBody:

    face: fusion.BRepFace = faces[0]

    axisZ: core.Vector3D = get_axis_vector(face)
    axisZ.normalize()
    axisX: core.Vector3D = get_unique_vector(axisZ)
    axisY: core.Vector3D = axisX.crossProduct(axisZ)

    tmpMgr: fusion.TemporaryBRepManager = fusion.TemporaryBRepManager.get()
    clone: fusion.BRepBody = tmpMgr.copy(face)
    [tmpMgr.booleanOperation(clone, tmpMgr.copy(f), fusion.BooleanTypes.UnionBooleanType)
        for f in faces]

    bbox: core.OrientedBoundingBox3D = get_bbox(
        clone,
        axisX,
        axisY,
    )

    ratio = bbox.height * 0.5 + 0.001
    points = []
    for length in (ratio, -ratio):
        v: core.Vector3D = axisZ.copy()
        v.scaleBy(length)
        p: core.Point3D = bbox.centerPoint.copy()
        p.translateBy(v)
        points.append(p)

    radius = get_radius(face)

    cylBody: fusion.BRepBody = tmpMgr.createCylinderOrCone(
        points[0],
        radius,
        points[1],
        radius,
    )

    return draw_bodies([cylBody])[0]


def add_offset_faces(
    faces: list,
    value: float,
) -> fusion.OffsetFacesFeature:

    try:
        app: core.Application = core.Application.get()
        face: fusion.BRepFace = faces[0]
        body: fusion.BRepBody = face.body
        comp: fusion.Component = body.parentComponent

        offsetFeats: fusion.OffsetFacesFeatures = comp.features.offsetFacesFeatures
        offsetCount = offsetFeats.count

        ui: core.UserInterface = app.userInterface
        sels: core.Selections = ui.activeSelections
        sels.clear()
        [sels.add(f) for f in faces]
        cmds = [
            u'Commands.Start FusionPressPullCommand',
            u'Commands.SetString infoOffsetType {}'.format('addNewOffset'),
            u'Commands.SetDouble OffsetFacesDistanceInput {}'.format(value),
            u'NuCommands.CommitCmd',
        ]

        [app.executeTextCommand(cmd) for cmd in cmds]

        if offsetFeats.count > offsetCount:
            return offsetFeats[-1]
        else:
            return None

    except:
        return None


def diff_body(
    targetBody: fusion.BRepBody,
    toolBody: fusion.BRepBody,
) -> fusion.CombineFeature:

    comp: fusion.Component = targetBody.parentComponent

    objs: core.ObjectCollection = lst2col([toolBody])

    combineFeats: fusion.CombineFeatures = comp.features.combineFeatures
    combineIpt: fusion.CombineFeatureInput = combineFeats.createInput(
        targetBody,
        objs,
    )
    combineIpt.isNewComponent = False
    combineIpt.isKeepToolBodies = False
    combineIpt.operation = fusion.FeatureOperations.CutFeatureOperation

    return combineFeats.add(combineIpt)


def get_radius(
    face: fusion.BRepFace,
) -> float:

    facePnt: core.Point3D = face.pointOnFace
    eva: core.SurfaceEvaluator = face.evaluator

    _, prm = eva.getParameterAtPoint(facePnt)
    _, _, cr1, cr2 = eva.getCurvature(prm)

    return max([abs(1 / c) for c in (cr1, cr2) if c != 0])


def get_bbox(
    body: fusion.BRepBody,
    axisX: core.Vector3D,
    axisY: core.Vector3D,
) -> core.OrientedBoundingBox3D:

    app: core.Application = core.Application.get()
    measMgr: core.MeasureManager = app.measureManager

    return measMgr.getOrientedBoundingBox(
        body,
        axisY,
        axisX,
    )


def get_unique_vector(
    vec: core.Vector3D
) -> core.Vector3D:

    v: core.Vector3D = core.Vector3D.create(0,0,1)
    if vec.isParallelTo(v):
        v = core.Vector3D.create(1,0,0)

    return vec.crossProduct(v)


def get_axis_vector(
    face: fusion.BRepFace,
) -> core.Vector3D:

    facePnt: core.Point3D = face.pointOnFace
    eva: core.SurfaceEvaluator = face.evaluator

    _, prm = eva.getParameterAtPoint(facePnt)

    lineType = core.Line3D.classType()
    # test
    # geoEva: core.SurfaceEvaluator = face.geometry.evaluator

    prmSets = (
        (prm.x, False),
        (prm.x, True),
        (prm.y, False),
        (prm.y, True),
    )
    for prm, isU in prmSets:
        resLst = eva.getIsoCurve(prm, isU)
        for res in resLst:
            # test
            # pp1 = geoEva.isClosedInU
            # pp2 = geoEva.isClosedInV
            if res.objectType == lineType:
                return res.asInfiniteLine().direction

    return None


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

    return [x for x in col]


def lst2col(
    lst: list,
) -> core.ObjectCollection:

    objs: core.ObjectCollection = core.ObjectCollection.create()
    [objs.add(x) for x in lst]
    return objs



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

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



def draw_bodies(
    bodyLst: list,
    targetOcc: fusion.Occurrence = None
) -> list:
    '''
    bodyの出力
    '''

    app: core.Application = core.Application.get()
    des: fusion.Design = app.activeProduct
    if not targetOcc:
        comp: fusion.Component = des.rootComponent
    else:
        comp: fusion.Component = targetOcc.component

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

    bodies: fusion.BRepBodies = comp.bRepBodies
    resBodies = []
    if baseFeat:
        baseFeat.startEdit()
        resBodies = [bodies.add(body, baseFeat) for body in bodyLst]
        baseFeat.finishEdit()

        return baseFeat.bodies
    else:
        return [bodies.add(body) for body in bodyLst]

念の為お伝えしておくと、このスクリプトは完成度が低いです。
場合によっては、Fusion360クラッシュするし、テストしたデータで
開けなくなるものが、2件出来ました。
使わない方が良いと思います。