C#ATIA

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

マウスカーソルの座標値を取得する6

こちらの続きです。
マウスカーソルの座標値を取得する5 - C#ATIA

取り組んでいる時間が無さそうなので、現状のものを公開しておきます。
そこそこ機能するはずです。

#FusionAPI_python
#Author-kantoku
#Description-MouseMoveTest ver0.0.3

import adsk.core, adsk.fusion, traceback
import math

_ui  = None
_handlers = []
_faces = []
_covunit = 0
_defLenUnit = ''
_draftVec = None

#選択面変更
class MyCommandInputChangedHandler(adsk.core.InputChangedEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            eventArgs = adsk.core.InputChangedEventArgs.cast(args)
    
            if eventArgs.input.id != 'DraftVec':
                return
                
            selectionInput = adsk.core.SelectionCommandInput.cast(eventArgs.input)
            print(selectionInput.selectionCount)
            
            global _draftVec
            if selectionInput.selectionCount == 0 :
                app = adsk.core.Application.get()
                des = adsk.fusion.Design.cast(app.activeProduct)
                comp = des.rootComponent
                vecZ = comp.zConstructionAxis.geometry.direction
                _draftVec = vecZ
                return
            
            ent = selectionInput.selection(0).entity
            vec = None
            if ent.classType() == 'adsk::fusion::SketchLine':
                vec = ent.worldGeometry.asInfiniteLine().direction
            _draftVec = vec
            
        except:
            global _ui
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

#このコマンドのイベント・ダイアログ作成
class MyCommandCreatedHandler(adsk.core.CommandCreatedEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            global _handlers
            cmd = adsk.core.Command.cast(args.command)
            
            #破棄
            onDestroy = MyCommandDestroyHandler()
            cmd.destroy.add(onDestroy)
            _handlers.append(onDestroy)
            
            #勾配向き
            onInputChanged = MyCommandInputChangedHandler()
            cmd.inputChanged.add(onInputChanged)
            _handlers.append(onInputChanged)
            
            #マウス
            onMouseMove = MyMouseMoveHandler()
            cmd.mouseMove.add(onMouseMove)
            _handlers.append(onMouseMove)
            
            inputs = cmd.commandInputs
            
            inputs.addTextBoxCommandInput('Pos', 'マウス3D座標値 :', 'Non!', 1, True)
            inputs.addTextBoxCommandInput('MinR', '最小R :', '-', 1, True)
            inputs.addTextBoxCommandInput('Ang', '角度 :', '-', 1, True)
            
            selInput = inputs.addSelectionInput('DraftVec', '角度基準', 'DraftVec')
            selInput.setSelectionLimits(0,1)

            selInput.selectionfilters = ['SketchLines']
            
        except:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
            
#このコマンドの破棄
class MyCommandDestroyHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            adsk.terminate()
        except:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

#MouseMoveイベント
class MyMouseMoveHandler(adsk.core.MouseEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        eventArgs = adsk.core.MouseEventArgs.cast(args)
        cmd = eventArgs.firingEvent.sender
        inputs = cmd.commandInputs
        
        #ビューポイント
        vp = eventArgs.viewport

        pos_ui = inputs.itemById('Pos')
        minr_ui = inputs.itemById('MinR')
        ang_ui = inputs.itemById('Ang')

        #マウス3D座標値
        onface = OnFace(vp, eventArgs.viewportPosition)
        if onface == None:
            pos_ui.text = 'Non!'
            minr_ui.text = '-'
            ang_ui.text = '-'
            return
        else:
            pos_ui.text = 'x:{:.3f} y:{:.3f} z:{:.3f}'.format(
                onface[1].x * _covunit,
                onface[1].y * _covunit,
                onface[1].z * _covunit)
                
        #法線
        ang_ui.text = '{:.3f} deg'.format(math.degrees(GetNomal(onface[0], onface[1])))
        
        #曲率
        cture = GetCurvature(onface[0], onface[1])
        if cture == None:
            minr_ui.text = '-'
        else:
            if round(cture,4) != 0 :
                crv_info = '{:.3f}{}'.format(
                        1 / cture * _covunit * -1, 
                        _defLenUnit)
                minr_ui.text = crv_info
            else:
                minr_ui.text = '-'

#法線
def GetNomal(face, pnt):
    eva = face.evaluator
    res, pram = eva.getParameterAtPoint(pnt)
    returnValue, normal = eva.getNormalAtPoint(pnt)
    ang = _draftVec.angleTo(normal)
    
    if ang > math.pi * 0.5 :
        ang = (math.pi * -1) + ang
    return ang
    
#曲率
def GetCurvature(face, pnt):
    if face.geometry.classType() == 'adsk::core::Plane':
        return None
    
    eva = face.evaluator
    res, pram = eva.getParameterAtPoint(pnt)
    returnValue, maxTangent, maxCurvature, minCurvature = eva.getCurvature(pram)
    
    if returnValue:
        return maxCurvature
    return None

#マウスカーソルの3D取得
def OnFace(vp, vp_pos):
    d3pos = vp.viewToModelSpace(vp_pos)
    cam = vp.camera
    vec = cam.eye.vectorTo(cam.target)
    
    pnt = adsk.core.Point3D.create(
        d3pos.x + vec.x, 
        d3pos.y + vec.y, 
        d3pos.z + vec.z)
        
    mouse3d = adsk.core.Line3D.create(d3pos, pnt).asInfiniteLine()    
    
    ints = [(face, mouse3d.intersectWithSurface(geo))
            for (face, geo) in _faces if mouse3d.intersectWithSurface(geo).count > 0]
    
    ints = [(face, p) 
            for (face, pnts) in ints
            for p in pnts]

    ints = [(face, p, face.evaluator.getParameterAtPoint(p))
            for (face, p) in ints]
    
    ints = [(face, p, prm)
            for (face, p, (res, prm)) in ints if res]
    
    ints = [(face, p, prm)
            for (face, p, prm) in ints]
            
    ints = [(face, p, cam.eye.distanceTo(p))
            for (face, p, prm) in ints if face.evaluator.isParameterOnFace(prm)]
    
    if len(ints) < 1:
        return None
    
    return min(ints, key = (lambda x: x[2]))
    
def run(context):
    try:
        global _ui
        app = adsk.core.Application.get()
        _ui = app.userInterface
                
        cmdDef = _ui.commandDefinitions.itemById('Mouse_Move_Test')
        if not cmdDef:
            cmdDef = _ui.commandDefinitions.addButtonDefinition(
                'Mouse_Move_Test', 
                'Mouse_Move_Test', 
                'Mouse_Move_Test')

        onCommandCreated = MyCommandCreatedHandler()
        cmdDef.commandCreated.add(onCommandCreated)
        _handlers.append(onCommandCreated)
        
        des = adsk.fusion.Design.cast(app.activeProduct)
        
        #全サーフェス取得
        global _faces
        _faces = [(face, face.geometry)
            for comp in des.allComponents if comp.isBodiesFolderLightBulbOn
            for bBody in comp.bRepBodies if bBody.isLightBulbOn & bBody.isVisible
            for face in bBody.faces]

        #単位準備
        global _covunit, _defLenUnit
        unitsMgr = des.unitsManager
        _defLenUnit = unitsMgr.defaultLengthUnits
        _covunit = unitsMgr.convert(1, unitsMgr.internalUnits, _defLenUnit)
        
        #角度基準
        global _draftVec
        comp = des.rootComponent
        _draftVec = comp.zConstructionAxis.geometry.direction

        cmdDef.execute()

        adsk.autoTerminate(False)
    except:
        if _ui:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

スプリクト実行した際、こんなダイアログが出現します。
f:id:kandennti:20180608122844p:plain
マウス3D座標値:マウスカーソル位置の3D座標です。面の上になっていない場合は表示されません。
 又、未テストですがコンポーネントを移動・回転させている場合は、正しい位置を表示しません。
最小R:凸をプラス 凹をマイナスでRサイズを表示します。
角度:"角度基準" 未指定の場合、ルートコンポーネントのZ軸を元に角度を表示します。
 水平を0° 垂直を90° とし、アンダーカット部分ではマイナスで表示します。
角度基準:"角度" を表示させる際の基準となる向きを指定できます。
 現状はスケッチの直線のみです。(ここが現在のお悩み)