こちらの続きです。
スプリクトで2要素間の距離測定をしたい4 - C#ATIA
あちらのスクリプトをコマンドダイアログ(?)仕様に修正しました。
#FusionAPI_python #Author-kantoku #Description-GetExtremumPoint ver0.04 #曲線の指定方向の最大・最小位置に点を作成します。 import adsk.core, adsk.fusion, traceback _commandId = 'extremumPoint' _commandName = 'ExtremumPoint' _commandDescription = '曲線の指定方向の最大・最小位置に点を作成します。' _handlers = [] _scl = 100000 #遠くの平面用 _app = adsk.core.Application.get() if _app: _ui = _app.userInterface class ExtremumPointCommandExecuteHandler(adsk.core.CommandEventHandler): def __init__(self): super().__init__() def notify(self, args): try: command = args.firingEvent.sender inputs = command.commandInputs crvIpt = inputs[0]; crvSel = crvIpt.selection(0); dirIpt = inputs[1]; dirSel = dirIpt.selection(0); extremumPoint = ExtremumPoint(); extremumPoint.Execute(crvSel.entity, dirSel.entity); except: if _ui: _ui.messageBox('エラー:\n{}'.format(traceback.format_exc())) class ExtremumPointCommandDestroyHandler(adsk.core.CommandEventHandler): def __init__(self): super().__init__() def notify(self, args): try: adsk.terminate() except: if _ui: _ui.messageBox('エラー:\n{}'.format(traceback.format_exc())) class ExtremumPointValidateInputHandler(adsk.core.ValidateInputsEventHandler): def __init__(self): super().__init__() def notify(self, args): try: sels = _ui.activeSelections; if len(sels) == 2: args.areInputsValid = True else: args.areInputsValid = False except: if _ui: _ui.messageBox('エラー:\n{}'.format(traceback.format_exc())) class ExtremumPointCommandCreatedHandler(adsk.core.CommandCreatedEventHandler): def __init__(self): super().__init__() def notify(self, args): try: cmd = args.command onExecute = ExtremumPointCommandExecuteHandler() cmd.execute.add(onExecute) onDestroy = ExtremumPointCommandDestroyHandler() cmd.destroy.add(onDestroy) onValidateInput = ExtremumPointValidateInputHandler() cmd.validateInputs.add(onValidateInput) _handlers.append(onExecute) _handlers.append(onDestroy) _handlers.append(onValidateInput) inputs = cmd.commandInputs i1 = inputs.addSelectionInput('crvIpt', '対象のエッジ', 'ボディ・パッチのエッジを選択') i1.addSelectionFilter(adsk.core.SelectionCommandInput.Edges); i2 = inputs.addSelectionInput('dirIpt', '向きとなる直線・平面', '向きとなる直線・平面を選択') i2.addSelectionFilter(adsk.core.SelectionCommandInput.PlanarFaces); i2.addSelectionFilter(adsk.core.SelectionCommandInput.LinearEdges); i2.addSelectionFilter(adsk.core.SelectionCommandInput.SketchLines); i2.addSelectionFilter(adsk.core.SelectionCommandInput.ConstructionLines); i2.addSelectionFilter(adsk.core.SelectionCommandInput.ConstructionPlanes); except: if _ui: _ui.messageBox('エラー:\n{}'.format(traceback.format_exc())) class ExtremumPoint: def Execute(self, crvSel, dirSel): #ラインから単位ベクトル取得 #param: line-line3d,SketchLine,BRepFace,Plane #return: vector3d def GetVec(line): if isinstance(line,adsk.fusion.SketchLine): geo = line.worldGeometry else: geo = line.geometry eva = geo.evaluator if isinstance(eva,adsk.core.SurfaceEvaluator): res, vec = eva.getNormalAtParameter(adsk.core.Point2D.create(0,0)) else: res, startPrm, endPrm = eva.getParameterExtents() res, vec = eva.getTangent(startPrm) vec.normalize() return vec #最短距離となる点の取得 #param: pnt-list(point3d), crv-curve3d #return: Point3D def GetMinimumPointAtPoint(pnts,crv): minpnts =[GetMinimumPointAtCurve(p,crv.geometry) for p in pnts] if len(minpnts) < 2: return None res =[(p1.distanceTo(p2),p2) for (p1,p2) in zip(pnts,minpnts)] try: (res,minPnt) = min(res) except: minPnt = res[0][1] return minPnt #点-線間の最短位置取得 #param: pnt-point3d, edg-curve3d #return: point3d def GetMinimumPointAtCurve(pnt, edg): try: eva = edg.evaluator res, prm = eva.getParameterAtPoint(pnt) if res is False:return None res, minPnt = eva.getPointAtParameter(prm) if res is False:return None return minPnt except: return None #点作成 #param: comp-Component, pnt3d-point3d #return - constructionPoint def CreatePnt(comp, pnt3d): pnt = comp.constructionPoints.createInput() pnt.setByPoint(adsk.core.Point3D.create(pnt3d.x, pnt3d.y, pnt3d.z)) return comp.constructionPoints.add(pnt) #選択 #param: ui-userInterface, msg-string, selFilter-SelectionFilters #return: entity def Sel(ui, msg, selFilter): try: return ui.selectEntity(msg, selFilter).entity except: return None #パラメトリックチェック #return: boolen def IsParametric(): app = adsk.core.Application.get() isPara = False design = adsk.fusion.Design.cast(app.activeProduct) if design.designType == adsk.fusion.DesignTypes.ParametricDesignType: isPara = True return isPara #range関数を実数に拡張したジェネレータ関数 #http://yu-write.blogspot.jp/2013/11/python-range.html #param: begin-float, end-float, step-float #return: generator(list(float)) def drange(begin, end, step): n = begin while n+step < end: yield n n += step #比較点郡取得 #param: vec-vector3d, crv-curve3d, scl-double #return: point3d() def GetComparisonPnts(vec, crv, scl): #変換行列設定 zaxis = adsk.core.Vector3D.create(0,0,1) mat3d = adsk.core.Matrix3D.create() mat3d.setToRotateTo(vec,zaxis) remat3d = adsk.core.Matrix3D.create() remat3d = mat3d.copy() remat3d.invert() mat3dpjt = adsk.core.Matrix3D.create() mat3dpjt.setWithArray((1,0,0,0, 0,1,0,0, 0,0,0,0, 0,0,0,1)) mat3dscl = adsk.core.Matrix3D.create() mat3dscl.setWithArray((scl,0,0,0, 0,scl,0,0, 0,0,scl,0, 0,0,0,1)) mat3d.transformBy(mat3dpjt) mat3d.transformBy(remat3d) mat3d.transformBy(mat3dscl) crveva = crv.geometry.evaluator (res,sprm,eprm) = crveva.getParameterExtents() (res,pnts) = crveva.getStrokes(sprm,eprm,0.001) [pnt.transformBy(mat3d) for pnt in pnts] return pnts def sss(path,txt): f = open(path, 'w') for t in txt: f.write('{}:{}\n'.format(t[0],t[1].asArray())) f.close() try: #向きベクトル global _scl vec = GetVec(dirSel) scls = [_scl*v for v in (1,-1)] #極値取得 mins = [] for scl in scls: #評価用点郡取得 pnts = GetComparisonPnts(vec, crvSel, scl) #最短点取得 mins.append(GetMinimumPointAtPoint(pnts, crvSel)) #作業コンポーネント取得 crvCmp = crvSel.body.parentComponent #点の作成 for minPnt in mins: if minPnt is None: continue if IsParametric(): baseF = crvCmp.features.baseFeatures.add() baseF.startEdit() CreatePnt(crvCmp, minPnt) baseF.finishEdit() else: CreatePnt(crvCmp, minPnt) _ui.messageBox('終了') except: if _ui: _ui.messageBox('エラー\n{}'.format(traceback.format_exc())) def run(context): try: product = _app.activeProduct design = adsk.fusion.Design.cast(product) if not design: _ui.messageBox('モデルワークスペースで実行してください') return commandDefinitions = _ui.commandDefinitions cmdDef = commandDefinitions.itemById(_commandId) if not cmdDef: cmdDef = commandDefinitions.addButtonDefinition(_commandId, _commandName, _commandDescription) onCommandCreated = ExtremumPointCommandCreatedHandler() cmdDef.commandCreated.add(onCommandCreated) _handlers.append(onCommandCreated) inputs = adsk.core.NamedValues.create() cmdDef.execute(inputs) adsk.autoTerminate(False) except: if _ui: _ui.messageBox('エラー:\n{}'.format(traceback.format_exc()))
何度も書きますが、苦手なんですイベント処理。
素直にサンプルのIntersectionsスプリクトをパクリました。
スクリプト実行後は、こんな感じのダイアログが出るので前回までのものより
わかりやすいかと思います。
又、Undoで "ExtremumPoint" と表示されるようにしました。
スプリクトでは2個点を作成しますが、1回のUndoで2個とも削除されます。
追記です。(Ver0.04)
一時的な要素の作成を止めたため、新規にコンポーネントを作成する際
デフォルトの名前が連番になるようにしました。