以前こちらで作成したCATIAのマクロをFusion360用にしてみました。
曲線と戦ってみる9 - C#ATIA
#FusionAPI_python #Author-kantoku #Description-ArcApproximation #スケッチ曲線の円弧近似化 import adsk.core, adsk.fusion, adsk.cam, traceback def run(context): ui = None #円弧近似化トレランス 単位はCm!! tolerance = 0.001 try: app = adsk.core.Application.get() ui = app.userInterface #面選択 selFilters = 'SketchCurves' sel = Sel('カーブを選択/ESC-中止', selFilters ) if sel is None: return crv = sel.entity #点群 points = InitPointsOnCurve(crv.geometry, tolerance) #円弧近似 threeArcs = [] threeArcs = InitThreePointArc(0, len(points)-1, tolerance, points, threeArcs) if len(threeArcs) < 1: ui.messageBox('円弧近似化できませんでした') return #スケッチ作成 des = adsk.fusion.Design.cast(app.activeProduct) comp = des.rootComponent skt = comp.sketches.add(comp.xYConstructionPlane) skt.name = "ArcApproximation" #円弧作成 skt_arcs = skt.sketchCurves.sketchArcs [skt_arcs.addByThreePoints(p1,p2,p3) for (p1,p2,p3) in threeArcs] ui.messageBox('{}個の円弧を作成しました'.format(len(threeArcs))) except: if ui: ui.messageBox('エラー\n{}'.format(traceback.format_exc())) #外心円 def GetCircumCircleOFTraiangle(p1,p2,p3): #3点ベクトル取得 vec1_2 = adsk.core.Vector3D.cast(p2.asVector()) vec1_2.subtract(p1.asVector()) vec1_2.normalize() vec2_3 = adsk.core.Vector3D.cast(p3.asVector()) vec2_3.subtract(p2.asVector()) vec2_3.normalize() #平行チェック if vec1_2.isParallelTo(vec2_3): return None #P2_P3間 オイラー線 eulerLine = vec2_3.crossProduct(vec1_2.crossProduct(vec2_3)) eulerLine.normalize() #中間点 p1_2 = GetMidPoint3D(p1,p2) p2_3 = GetMidPoint3D(p2,p3) #不明 nv = vec1_2.dotProduct(eulerLine) t = (vec1_2.dotProduct(p1_2.asVector()) - vec1_2.dotProduct(p2_3.asVector())) / nv #外心 center = GetCircumCenter(p2_3,eulerLine,t) #半径 radius = center.distanceTo(p1) return (center, radius) #外心 def GetCircumCenter(p,v,l): pos = (p.x + v.x * l, p.y + v.y * l, p.z + v.z * l) return adsk.core.Point3D.create(pos[0],pos[1],pos[2]) #中間点 def GetMidPoint3D(p1,p2): pos = ((p1.x + p2.x) * 0.5, (p1.y + p2.y) * 0.5, (p1.z + p2.z) * 0.5) return adsk.core.Point3D.create(pos[0],pos[1],pos[2]) def IsInTolerance(center, radius, tol, points): dist_lst = [radius - center.distanceTo(p) for p in points] res = [d for d in dist_lst if d > tol] return True if len(res) < 1 else False #3点円弧 再帰 def InitThreePointArc(startIdx, endIdx, tol, points, threeArcs): if 2 > (endIdx - startIdx): return threeArcs #中間idx midIdx = int((startIdx + endIdx) * 0.5) arc = GetCircumCircleOFTraiangle(points[startIdx], points[midIdx], points[endIdx]) if arc is None: return threeArcs #円弧評価 if IsInTolerance(arc[0], arc[1], 0.001, points[startIdx+1:endIdx-1]): threeArcs.append([points[startIdx],points[midIdx],points[endIdx]]) else: threeArcs = InitThreePointArc(startIdx, midIdx, tol, points, threeArcs) threeArcs = InitThreePointArc(midIdx, endIdx, tol, points, threeArcs) return threeArcs #トレランス以内の曲線上の点群 def InitPointsOnCurve(geo, tol): #evaluator eva = geo.evaluator #始点終点 (returnValue, startPoint, endPoint) = eva.getEndPoints() (returnValue, startPram) = eva.getParameterAtPoint(startPoint) (returnValue, endPram) = eva.getParameterAtPoint(endPoint) #トレランス以内の点群 (returnValue, pnts) = eva.getStrokes(startPram, endPram, tol) return pnts #選択 def Sel(msg, selFilter): app = adsk.core.Application.get() ui = app.userInterface try: return ui.selectEntity(msg, selFilter) except: return None
役に立つものかどうかは、かなり謎です。
CATIAに比べ、Fusion360APIはベクトルのクラスが既存であり
ベクトル演算が簡単に行えるのはかなり楽です。(破壊的・非破壊的メソッドの違いには迷う)
又、折れ線近似化する事が可能なトレランス以内で点群を取得できるメソッド(getStrokes)が
備わっているのもかなり楽です。
処理自体もCATIAより軽い気もしますね。