こちらで質問したものをスクリプトにしました。
解決済み: 曲面の境界のオフセットラインを取得 - Autodesk Community
結果的にパイプ+面分割の方法で行ってみました。
例外処理とかほぼしていませんので、あまり無茶は出来ませんので。
# 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 = 'Select' selFilter: str = 'Faces' sel: adsk.core.Selection = selectEnt(msg, selFilter) if not sel: return valStr, res = ui.inputBox( 'オフセット距離を入力', '外周のオフセット線', '1.0' ) if res: return if not valStr.isdecimal(): return initOffsetEdges(sel.entity, float(valStr)) except: if ui: ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) def initOffsetEdges( face: adsk.fusion.BRepFace, offsetLength: float): if not offsetLength > 0: return app: adsk.core.Application = adsk.core.Application.get() des: adsk.fusion.Design = app.activeProduct root: adsk.fusion.Component = des.rootComponent comp: adsk.fusion.Component = root # 元面のクローン tmpMgr: adsk.fusion.TemporaryBRepManager = adsk.fusion.TemporaryBRepManager.get() clone: adsk.fusion.BRepBody = tmpMgr.copy(face) baseFeat: adsk.fusion.BaseFeature = None if des.designType == adsk.fusion.DesignTypes.ParametricDesignType: baseFeat = comp.features.baseFeatures.add() bodies: adsk.fusion.BRepBodies = comp.bRepBodies cloneFace: adsk.fusion.BRepFace = None if baseFeat: baseFeat.startEdit() try: cloneFace = bodies.add(clone, baseFeat).faces[0] except: pass else: try: cloneFace = bodies.add(clone) except: pass # 境界 loops = [l for l in cloneFace.loops] # 元エッジのジオメトリ edges = [e for e in loops[0].edges] # ゴリゴリオフセットエッジの作成 plane: adsk.fusion.ConstructionPlane = initPlane(loops[0]) skt: adsk.fusion.Sketch = initSketch(plane, offsetLength) sweepBody: adsk.fusion.BRepBody = initSweep(loops[0], skt) initSplitBody(cloneFace, sweepBody) sweepBody.deleteMe() skt.deleteMe() plane.deleteMe() if baseFeat: baseFeat.finishEdit() # オフセットジオメトリの取得 geos = getOffsetCurves(cloneFace, edges) if baseFeat: baseFeat.deleteMe() # オフセットエッジを描く! offsetSkt: adsk.fusion.Sketch = initSketch(root.xYConstructionPlane) splines: adsk.fusion.SketchFixedSplines = offsetSkt.sketchCurves.sketchFittedSplines offsetSkt.isComputeDeferred = True offsetSkt.arePointsShown = False for geo in geos: if hasattr(geo, 'asNurbsCurve'): geo = geo.asNurbsCurve spline: adsk.fusion.SketchFixedSpline = splines.addByNurbsCurve(geo) spline.isReference = False offsetSkt.isComputeDeferred = False def getOffsetCurves( face: adsk.fusion.BRepFace, edges: list) -> list: geos = [] for f in face.body.faces: for e in f.edges: if not isIncludedEdge(e, edges): geos.append(e.geometry) return geos def isIncludedEdge( edge: adsk.fusion.BRepEdge, edges: list) -> bool: for e in edges: if isEqEdge(edge, e): return True return False def isEqEdge( e1: adsk.fusion.BRepEdge, e2: adsk.fusion.BRepEdge) -> bool: if e1.geometry.objectType != e2.geometry.objectType: return False app: adsk.core.Application = adsk.core.Application.get() if e1.length - e2.length > app.pointTolerance: return False measMgr: adsk.core.MeasureManager = app.measureManager vecL: adsk.core.Vector3D = adsk.core.Vector3D.create(0,1,0) vecW: adsk.core.Vector3D = adsk.core.Vector3D.create(1,0,0) bBox1: adsk.core.OrientedBoundingBox3D = measMgr.getOrientedBoundingBox( e1, vecL, vecW ) bBox2: adsk.core.OrientedBoundingBox3D = measMgr.getOrientedBoundingBox( e2, vecL, vecW ) if not bBox1.centerPoint.isEqualTo(bBox2.centerPoint): return False if bBox1.length - bBox2.length > app.pointTolerance: return False if bBox1.width - bBox2.width > app.pointTolerance: return False if bBox1.height - bBox2.height > app.pointTolerance: return False return True def initSplitBody( targetFace: adsk.fusion.BRepFace, toolBody: adsk.fusion.BRepBody) -> adsk.fusion.BRepBody: comp: adsk.fusion.Component = targetFace.body.parentComponent objs: adsk.core.ObjectCollection = adsk.core.ObjectCollection.create() objs.add(targetFace) splitFaceFeats: adsk.fusion.SplitFaceFeatures = comp.features.splitFaceFeatures splitIpt: adsk.fusion.SplitFaceFeatureInput = splitFaceFeats.createInput( objs, toolBody, True ) splitFaceFeat: adsk.fusion.SplitFaceFeature = splitFaceFeats.add(splitIpt) def initSweep( loop: adsk.fusion.BRepLoop, skt: adsk.fusion.Sketch) -> adsk.fusion.BRepBody: comp: adsk.fusion.Component = skt.parentComponent objs: adsk.core.ObjectCollection = adsk.core.ObjectCollection.create() [objs.add(e) for e in loop.edges] path: adsk.fusion.Path = comp.features.createPath( objs, True ) sweepFeats: adsk.fusion.SweepFeatures = comp.features.sweepFeatures sweepIpt: adsk.fusion.SweepFeatureInput = sweepFeats.createInput( skt.profiles[0], path, adsk.fusion.FeatureOperations.NewBodyFeatureOperation ) sweepFeat: adsk.fusion.SweepFeature = sweepFeats.add(sweepIpt) return sweepFeat.bodies[0] def initSketch( plane: adsk.fusion.ConstructionPlane, radius: float = -1) -> adsk.fusion.Sketch: comp: adsk.fusion.Component = plane.component skt: adsk.fusion.Sketch = comp.sketches.add(plane) if radius > 0: skt.sketchCurves.sketchCircles.addByCenterRadius( skt.originPoint, radius ) return skt def initPlane( loop: adsk.fusion.BRepLoop) -> adsk.fusion.ConstructionPlane: # ここOCC関係あるかも comp: adsk.fusion.Component = loop.body.parentComponent planes: adsk.fusion.ConstructionPlanes = comp.constructionPlanes planeIpt: adsk.fusion.ConstructionPlaneInput = planes.createInput() planeIpt.setByDistanceOnPath( loop.edges[0], adsk.core.ValueInput.createByReal(0) ) return planes.add(planeIpt) 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
クッソ長くなったのは、APIでパイプコマンドが無い為、スイープで
代替えしている為です。
出来が悪いのですが、ここがゴールでは無いのでご勘弁を。