C#ATIA

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

デフォルト [コンポーネント/残り代] と異なる設定のツールパス名を取得2

こちらの続きです。
デフォルト [コンポーネント/残り代] と異なる設定のツールパス名を取得 - C#ATIA

前回はコンポーネント数は未チェックでしたが、チェックするように修正し
実際に使えそうなレベルにして見ました。

//pm2018 macro
//Find_don't_match_ToolPath.mac ver0.0.2
//デフォルト [コンポーネント/残り代] と異なる設定のツールパス名取得
//---------------------------------------------------------------------------------------------------
//ver0.0.1-完成
//ver0.0.2-コンポーネントチェック追加
//---------------------------------------------------------------------------------------------------

function main() {
	bool debug = 0 //debug mode
	
	//check
	call CanExec()
	
	//start
	call Sw_Start()
	graphics lock

	INFOBOX NEW "***** Toolpath ThicknessSetValues info *****"
	INFOBOX CLEAR FORMAT
	
	//defalt ThicknessSetValues
	call PushInfobox('Getting Surface Defaults Info.' + crlf)
	string list def_tvInfo = {}
	string def_cmp_count = ''
	call Get_defalt_ThicknessSetValuesInfo($def_tvInfo, $def_cmp_count)
	
	//filter
	call PushInfobox('Getting Toolpath Surface Parameter.' + crlf)
	string filter = ''
	call Initfilter($def_tvInfo, $filter)
	
	//pram match toolpath
	entity list tps = folder('toolpath')
	$tps =  filter($tps , $filter)
	
	//components
	call PushInfobox('Getting Toolpath Surface Components')
	string list cmps = {}
	call GetCompsCount($tps, $cmps)
	
	//&components match toolpath
	call GetCompMatchList($tps, $cmps, $def_cmp_count, $tps)
	
	//doesn't match toolpath
	call PushInfobox("Getting doesn't match Toolpath." + crlf + crlf)
	string list all_tps =  extract(folder('toolpath'), 'name') 
	string list match_tps =  extract($tps, 'name') 
	string list unmatch_tps =  subtract($all_tps, $match_tps)
	
	call PushInfobox('デフォルト [コンポーネント/残り代] と異なる設定のツールパスは以下のものです' + crlf)
	//call PushInfobox("It's toolpath that don't match the 'Surface Defaults' values." + crlf)
	call PushInfobox(join($unmatch_tps, crlf))
	
	//finish
	if $debug == 1 {
		string tm = ''
		call Sw_GetTime($tm)
		call PushInfobox(crlf + $tm)
	}
	message info  'Done'
}

//start check
function CanExec() {
	string list msg = {}
	int dmy = 0
	//toolpath
	if size(folder('toolpath')) <1 {
		 $dmy = add_last($msg, 'There is no toolpath to check.')
	}
	if size(folder('model')) <1 {
		 $dmy = add_last($msg, 'The model has not been imported.')
	}
	if not is_empty($msg) {
		message warn join($msg, crlf)
		macro abort
	}
}

//Match components
function GetCompMatchList(entity list tps, string list cmps, 
					string def_cmp, output entity list out) {
	int list rng = {}
	call GetRangeLst(0, size($tps), $rng)
	$rng = reverse($rng)
	bool dmy = 0
	foreach idx in $rng {
		if $cmps == $def_cmp {
			$dmy = remove($tps, $idx)
		}
	}
	$out = $tps
}

//Toolpath components
function GetToolpathCompsCount(entity tp, output string out) {
	int list tv_rng = {}
	call GetRangeLst(0, size($tp.ThicknessSetValues), $tv_rng)
	
	int list cmps = {}
	int dmy = 0
	int surf_cnt = -1
	
	foreach idx in $tv_rng {
		$surf_cnt = -1
		object tv =  $tp.ThicknessSetValues[$idx]
		DELETE SELECTION
		EDIT THICKNESS DEFAULTLIST UPDATE
		\r
		$idx  NEW
		\r
		EDIT THICKNESS SELECT
		call GetSelSurfCount($surf_cnt)
		$dmy = add_last($cmps, $surf_cnt)
	}
	$out = join($cmps, ',')
}

//toolpath_list components
function GetCompsCount(entity list tps, output string list out) {
	$out = {}
	string cmp = ''
	int dmy = 0
	foreach tp in tps {	
		call GetToolpathCompsCount($tp, $cmp)
		$dmy = add_last($out, $cmp)
		call PushInfobox(' .' )
	}
	call PushInfobox(crlf)
}

//select surface count
function GetSelSurfCount(output int num) {
	string $TraceFilePath = macro_path(false) + "\selsurf.txt"
	string list txts = {}
	ECHO OFF DCPDEBUG UNTRACE COMMAND ACCEPT
	TRACEFILE OPEN $TraceFilePath
	PRINT SELSURFACE
	TRACEFILE CLOSE
	ECHO ON DCPDEBUG TRACE COMMAND ACCEPT
	
	FILE OPEN $TraceFilePath FOR READ AS Input
	FILE READ $txts FROM Input
	FILE CLOSE Input
	DELETE FILE $TraceFilePath

	$num = size($txts) - 1
}

//filter
function Initfilter(string list tvs, output string out) {
	string list prms = {'Mode', 'UseAxialThickness', 'Thickness', 'AxialThickness'}
	int list prm_rng = {}
	call GetRangeLst(0, size($prms), $prm_rng)
	
	int list tv_rng = {}
	call GetRangeLst(0, size($tvs), $tv_rng)
	
	$out = ''
	string list tmp = {}
	int dmy = 0
	string value = ''
	foreach tv_idx in $tv_rng {
		string list info = tokens($tvs[$tv_idx], ',')
		foreach prm_idx in $prm_rng {
			if $prm_idx == 0 {
				$value = '"' + $info[$prm_idx] + '"'
			} else {
				$value = $info[$prm_idx]
			}
			$dmy = add_last($tmp, 'ThicknessSetValues[' + string($tv_idx) + '].' + $prms[$prm_idx] + ' == ' + $value)
		}
	}
	$out = join($tmp, ' and ')
	print = $out
}

//defalt ThicknessSetValues info
function Get_defalt_ThicknessSetValuesInfo(output string list out, output string cmpcnt) {
	string dmy_tp = ''
	call InitDmyTP($dmy_tp)
	entity tp = entity('toolpath', $dmy_tp)
	
	FORM THICKNESS EDIT THICKNESS TAB DEFAULT
	EDIT THICKNESS TAB COMPONENTS TOOLPATH	
	EDIT TOOLPATH ; THICKNESS CLONE_DEFAULT
	THICKNESS ACCEPT
	object list def_tvs = $tp.ThicknessSetValues
	call GetThickSetValInfo($def_tvs, $out)
	call GetToolpathCompsCount($tp, $cmpcnt)
	DELETE TOOLPATH  $dmy_tp	
}

//ThicknessSetValues info
function GetThickSetValInfo(object list tvs, output string list out) {
	int list rng = {}
	call GetRangeLst(0, size($tvs), $rng)
	string info =''
	string list lst = {}
	int dmy = 0
	
	foreach idx in $rng {
		object tv =  $tvs[$idx]
		$info = $tv.Mode + ',' + $tv.UseAxialThickness + ',' + $tv.Thickness + ',' + $tv.AxialThickness
		$dmy = add_last($lst, $info)
	}
	$out = $lst
}	

//dammy toolpath
function InitDmyTP(output string out) {
	$out = new_entity_name('toolpath')
	IMPORT TEMPLATE ENTITY TOOLPATH TMPLTSELECTORGUI 'Finishing/Constant-Z-Finishing.002.ptf'
	FORM CANCEL STRATEGYSELECTOR\nFORM TOOLPATHIMPORT
	EDIT TOOLPATH $out REAPPLYFROMGUI
	YES
	FORM ACCEPT SFConstZFinishing
}

//range
function GetRangeLst(int start, int count, output int list lst) {
	int num = 0
	$lst = {}
	do {
		int dmy = add_last($lst, $start + $num)
		$num = $num + 1
	} while $num < $count
}

//infobox
function PushInfobox(string msg) {
	INFOBOX STYLE "NORMAL"
	INFOBOX APPEND  $msg
}

//clock on
function Sw_Start() {
	CLOCK RESET QUIT
	CLOCK ON QUIT	
}

//clock off
function Sw_GetTime(output string out) {
	string $TraceFilePath = macro_path(false) + "\clock.txt"
	string list txts = {}
	ECHO OFF DCPDEBUG UNTRACE COMMAND ACCEPT
	TRACEFILE OPEN $TraceFilePath
	CLOCK OFF QUIT
	CLOCK PRINT QUIT
	TRACEFILE CLOSE
	ECHO ON DCPDEBUG TRACE COMMAND ACCEPT
	
	FILE OPEN $TraceFilePath FOR READ AS Input
	FILE READ $txts FROM Input
	FILE CLOSE Input
	DELETE FILE $TraceFilePath

	$out = $txts[0]
}

コメントが英語な部分は、そのうちフォーラムで良い方法が無いものか? を
質問しようと思っているためです。(コード内の英語を含め、自信なし)

実際に業務で使用したデータでチェックしてみました。
前回のマクロでは
f:id:kandennti:20180528151318p:plain
7秒ほど。

今回のマクロでは
f:id:kandennti:20180528151359p:plain
80秒ほど・・・・ガッカリ。
手動でチェックするのを考えれば、確かに速いけど、
マクロで1分以上はかなり苦痛。

デフォルト [コンポーネント/残り代] と異なる設定のツールパス名を取得

こちらの続きです。
ツールパスのコンポーネント残り代情報 - C#ATIA

テスト的なコードとは言え、あまりの処理の遅さのため改善します。
根本的な目的は、全ての情報の取得ではなく任意の設定となっていない
ツールパスさえわかれば良いのです。(修正は手動でチマチマ)

//pm2018 macro
//Get_ThicknessSetValues_Unmatch_ToolPath_Name.mac ver0.0.1
//デフォルト [コンポーネント/残り代] と異なる設定のツールパス名取得

function main() {
	call Sw_Start()
	graphics lock

	//defalt ThicknessSetValues
	string list def_tvInfo = {}
	call Get_defalt_ThicknessSetValuesInfo($def_tvInfo)
	
	//filter
	string filter = ''
	call Initfilter($def_tvInfo, $filter)
	
	//match toolpath
	entity list tps = folder('toolpath')
	$tps =  filter($tps , $filter)
	
	//un_match toolpath
	string list all_tps =  extract(folder('toolpath'), 'name') 
	string list match_tps =  extract($tps, 'name') 
	string list unmatch_tps =  subtract($all_tps, $match_tps)
	
	INFOBOX NEW "***** toolpath ThicknessSetValues info *****"
	INFOBOX CLEAR FORMAT
	call ShowInfobox('デフォルト [コンポーネント/残り代] と異なる設定のツールパスは以下のものです' + crlf)
	call ShowInfobox(join($unmatch_tps, crlf))
	
	//終了
	call Sw_GetTime()
}

//filter
function Initfilter(string list tvs, output string out) {
	string list prms = {'Mode', 'UseAxialThickness', 'Thickness', 'AxialThickness'}
	int list prm_rng = {}
	call GetRangeLst(0, size($prms), $prm_rng)
	
	int list tv_rng = {}
	call GetRangeLst(0, size($tvs), $tv_rng)
	
	$out = ''
	string list tmp = {}
	int dmy = 0
	string value = ''
	foreach tv_idx in $tv_rng {
		string list info = tokens($tvs[$tv_idx], ',')
		foreach prm_idx in $prm_rng {
			if $prm_idx == 0 {
				$value = '"' + $info[$prm_idx] + '"'
			} else {
				$value = $info[$prm_idx]
			}
			$dmy = add_last($tmp, 'ThicknessSetValues[' + string($tv_idx) + '].' + $prms[$prm_idx] + ' == ' + $value)
		}
	}
	$out = join($tmp, ' and ')
	print = $out
}

//defalt ThicknessSetValues info
function Get_defalt_ThicknessSetValuesInfo(output string list out) {
	string dmy_tp = ''
	call InitDmyTP($dmy_tp)
	
	FORM THICKNESS EDIT THICKNESS TAB DEFAULT
	EDIT THICKNESS TAB COMPONENTS TOOLPATH	
	EDIT TOOLPATH ; THICKNESS CLONE_DEFAULT
	THICKNESS ACCEPT
	object list def_tvs = entity('toolpath', $dmy_tp).ThicknessSetValues
	call GetThickSetValInfo($def_tvs, $out)
	DELETE TOOLPATH  $dmy_tp	
}

//ThicknessSetValues info
function GetThickSetValInfo(object list tvs, output string list out) {
	int list rng = {}
	call GetRangeLst(0, size($tvs), $rng)
	string info =''
	string list lst = {}
	int dmy = 0
	
	foreach idx in $rng {
		object tv =  $tvs[$idx]
		$info = $tv.Mode + ',' + $tv.UseAxialThickness + ',' + $tv.Thickness + ',' + $tv.AxialThickness
		$dmy = add_last($lst, $info)
	}
	$out = $lst
}	

//ダミーツールパス
function InitDmyTP(output string out) {
	$out = new_entity_name('toolpath')
	IMPORT TEMPLATE ENTITY TOOLPATH TMPLTSELECTORGUI 'Finishing/Constant-Z-Finishing.002.ptf'
	FORM CANCEL STRATEGYSELECTOR\nFORM TOOLPATHIMPORT
	EDIT TOOLPATH $out REAPPLYFROMGUI
	YES
	FORM ACCEPT SFConstZFinishing
}

//範囲
function GetRangeLst(int start, int count, output int list lst) {
	int num = 0
	$lst = {}
	do {
		int dmy = add_last($lst, $start + $num)
		$num = $num + 1
	} while $num < $count
}

//情報
function ShowInfobox(string msg) {
	INFOBOX STYLE "NORMAL"
	INFOBOX APPEND  $msg
}

//測定スタート
function Sw_Start() {
	CLOCK RESET QUIT
	CLOCK ON QUIT	
}

//時間表示
function Sw_GetTime() {
	string $TraceFilePath = macro_path(false) + "\clock.txt"
	string list txts = {}
	ECHO OFF DCPDEBUG UNTRACE COMMAND ACCEPT
	TRACEFILE OPEN $TraceFilePath
	CLOCK OFF QUIT
	CLOCK PRINT QUIT
	TRACEFILE CLOSE
	ECHO ON DCPDEBUG TRACE COMMAND ACCEPT
	
	FILE OPEN $TraceFilePath FOR READ AS Input
	FILE READ $txts FROM Input
	FILE CLOSE Input
	DELETE FILE $TraceFilePath

	message info $txts[0]
}

全ツールパスに対してフィルター関数で抜き出すのですが、フィルターの条件もForEachで作り出します。
PMillマクロのString型に文字数制限は無い?(ひょっとしたらあるのかな?)様で、
かなり巨大な文字列を渡しています。

比較対象はデフォルト [コンポーネント/残り代] の設定です。
f:id:kandennti:20180525194927p:plain

実際にテストした結果はこちら
f:id:kandennti:20180525194936p:plain

20本程のツールパスに対して、6秒弱! 正直、驚きました。
前回のものでは同様のデータで3分以上かかっていたので。
但し、前回紹介したコンポーネント数のチェックはしてません・・・。

フィルター関数使おう、ループは遅い。
(コンポーネント数をパラメータで取得したい)

PMillのマクロ時間測定

以前こちらに書いた中に関数のコードだけ載せていたのですが
ツールパスバッチ処理 時間測定 - C#ATIA
エコーコマンド部分に表示される為、ちょっと使いにくかったです。

その為「Sw_GetTime」だけ書き換えました。

function Sw_Start() {
	CLOCK RESET QUIT
	CLOCK ON QUIT	
}

function Sw_GetTime() {
	string $TraceFilePath = macro_path(false) + "\clock.txt"
	string list txts = {}
	ECHO OFF DCPDEBUG UNTRACE COMMAND ACCEPT
	TRACEFILE OPEN $TraceFilePath
	CLOCK OFF QUIT
	CLOCK PRINT QUIT
	TRACEFILE CLOSE
	ECHO ON DCPDEBUG TRACE COMMAND ACCEPT
	
	FILE OPEN $TraceFilePath FOR READ AS Input
	FILE READ $txts FROM Input
	FILE CLOSE Input
	DELETE FILE $TraceFilePath

	message info $txts[0]
}

これを利用すると、こんな風にダイアログで表示します。
f:id:kandennti:20180525172725p:plain
TRACEFILE OPEN ~ CLOSE は、コマンドエコーに出力されるものを
ファイルで取得出来るんですね。(PRINT PAR ~等)

ツールパスのコンポーネント残り代情報

PowerMillの機能に、コンポーネント残り代と言う機能があるのですが
一般的に使われるものかどうか?
個人的には電極の仕上代を設定する為、必ず使っています。

ところがここの設定の確認が非常にやりにくい為、マクロでチェックしようと
考えているのですが苦戦してます。
f:id:kandennti:20180524190219p:plain
殆どの情報は取得できるのですが、矢印のコンポーネント数を取得する
パラメータが存在しないようで困ってしまいました。

サポートさんに問い合わせても出来ないとの回答は頂いたのですが、
ちょっとだけ気が付いた事がありました。
各セットを選択した状態で、こちらの名称不明のボタンを押すと
コンポーネントとして登録された面を選択した状態になります。
f:id:kandennti:20180524190802p:plain
これを利用すれば、選択面の数を取得する事でコンポーネント数の
取得となりそうです。

//pm2018 macro
//全ツールパスのコンポーネント/残り代情報を垂れ流す

function main() {
	int list rng = {}
	call GetRangeLst(0, 16, $rng)
	
	INFOBOX NEW "***** toolpath ThicknessSetValues info *****"
	INFOBOX CLEAR FORMAT
	
	string info = ''	
	int surf_cnt = 0
	
	FORM THICKNESS EDIT THICKNESS TAB DEFAULT
	EDIT THICKNESS TAB COMPONENTS TOOLPATH
	THICKNESS ACCEPT

	dialogs error off
	dialogs message off
	
	foreach tp in folder('toolpath') {
		string full = pathname('toolpath', $tp)
		EXPLORER SELECT Toolpath $full  NEW
		$info = '-- toolpath : ' + $tp.name + ' --'+ crlf
		object list tvs = $tp.ThicknessSetValues
		foreach idx in $rng {
			object tv =  $tp.ThicknessSetValues[$idx]
			
			$info = $info + string($idx) + ' : '
			$info = $info + $tv.Mode + ' : '
			$info = $info + $tv.UseAxialThickness + ' : '
			$info = $info + string($tv.Thickness) + ' : '
			$info = $info + string($tv.AxialThickness) + ' : '
			
			//コンポーネント数の取得
			graphics lock
			DELETE SELECTION
			EDIT THICKNESS DEFAULTLIST UPDATE
			\r
			$idx  NEW
			\r
			EDIT THICKNESS SELECT
			graphics unlock
			call GetSelSurfCount($surf_cnt)
			$info = $info + string($surf_cnt) + crlf
		}
		$info = $info + crlf
		dialogs message on
		call ShowInfobox($info)
		dialogs message off
	}
	DELETE SELECTION
	dialogs message on
	dialogs error on
	
	//終了
	message info  'Done'		
}

function GetRangeLst(int start, int count, output int list lst) {
	int num = 0
	$lst = {}
	do {
		int dmy = add_last($lst, $start + $num)
		$num = $num + 1
	} while $num < $count
}

function GetSelSurfCount(output int num) {
	string $TraceFilePath = macro_path(false) + "\selsurf.txt"
	string list txts = {}
	ECHO OFF DCPDEBUG UNTRACE COMMAND ACCEPT
	TRACEFILE OPEN $TraceFilePath
	PRINT SELSURFACE
	TRACEFILE CLOSE
	ECHO ON DCPDEBUG TRACE COMMAND ACCEPT
	
	FILE OPEN $TraceFilePath FOR READ AS Input
	FILE READ $txts FROM Input
	FILE CLOSE Input
	DELETE FILE $TraceFilePath

	$num = size($txts) - 1
}	

function ShowInfobox(string msg) {
	INFOBOX STYLE "NORMAL"
	INFOBOX APPEND  $msg
}

テスト的なコードのため、InfoBoxに結果を垂れ流しているだけです。
・・・遅いんです、処理が。

原因は
・ツールパスをアクティブにしている
・毎回、面を選択している
・選択面数の取得にファイルの書き込み・読み込みをしている
だとは思うのですが、アクティブにしなくても良かったのかな?
選択面数の取得はこちらの方法です。
水平面高さリストを表示2 - C#ATIA
ファイルの書み・読みを1ツールパスに付き16回もやっているんです・・・。

イロイロ探して試しているのですが、選択面数ぐらい何とか取得出来そうな
気もするのですが・・・。

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

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

前回よくわからず、スコープを大きくした変数ですが、こんな感じにすると、
commandInputs が EventHandler の args から取得出来る事が判りました。
(commandInputs はVBAのフォームのようなもの)

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

他もチョロチョロ修正し、こんな感じです。

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

import adsk.core, traceback

_ui  = None
_handlers = []

#このコマンドのイベント・ダイアログ作成
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)

            onMouseMove = MyMouseMoveHandler()
            cmd.mouseMove.add(onMouseMove)
            _handlers.append(onMouseMove)

            inputs = cmd.commandInputs
            
            inputs.addTextBoxCommandInput('Vp_Pos', 'Fusion360画面上の座標値', '-', 1, True)
            inputs.addTextBoxCommandInput('Sc_Pos', 'ディスプレイ上の座標値', '-', 1, True)
            inputs.addTextBoxCommandInput('3D_Pos', 'マウス3D仮座標値', '-', 1, True)
            inputs.addTextBoxCommandInput('Cam_Vec', 'カメラ向き(単位ベクトル)', '-', 1, True)
        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
        
        #Fusion360画面上の座標値
        vppos = eventArgs.viewportPosition
        ui_vp = inputs.itemById('Vp_Pos')
        ui_vp.text = 'x:[%d] y:[%d]'%(vppos.x, vppos.y)
        
        #ディスプレイ上の座標値
        scrpos = vp.viewToScreen(vppos)
        ui_sc = inputs.itemById('Sc_Pos')
        ui_sc.text = 'x:[%d] y:[%d]'%(scrpos.x, scrpos.y)
        
        #マウス3D仮座標値-奥行きがNGな為正しくない(通過点)
        d3pos = vp.viewToModelSpace(vppos)
        d3_sc = inputs.itemById('3D_Pos')
        d3_sc.text = 'x:{:.3f} y:{:.3f} z:{:.3f}'.format(d3pos.x, d3pos.y, d3pos.z)
        
        #カメラ向き(単位ベクトル)
        cam = vp.camera
        vec = cam.eye.vectorTo(cam.target)
        vec.normalize()
        vec_sc = inputs.itemById('Cam_Vec')
        vec_sc.text = 'x:{:.3f} y:{:.3f} z:{:.3f}'.format(vec.x, vec.y, vec.z)        
        
def run(context):
    try:
        #global _app, _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)
        
        cmdDef.execute()

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

動作はこんな感じです。

マウス3D仮座標値はキューブの向きが上とかの向きになった場合のみ、
奥行き以外の座標値は正しく得られます。
ディスプレイが2Dな為に奥行きが確定せず、傾いた場合は全ての座標値が
正しく得られません。
マウスカーソルは3D空間上では、カメラ向き方向のベクトルでマウス3D仮座標値を
通過する状態になっているはず・・・確認していませんが。

カメラ向き方向のベクトルは、直接取得できるメソッドが無かった為、
カメラ位置からターゲットを単位ベクトル化しました。

        #カメラ向き(単位ベクトル)
        cam = vp.camera
        vec = cam.eye.vectorTo(cam.target)
        vec.normalize()

ターゲットが常に画面中央になっている事を前提で考えたのですが、
多分正しいよね?

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

先日、ちょこっとFusion360APIやった際に色々と調べていたら
発見したので記載。

よく探してみたら、同様のことをこちらでやってました…。
MouseMoveEvent サンプル - C#ATIA

前回やった際は、ディスプレイ上のマウスカーソル位置座標(左上が0,0)の取得しか
出来なかったのですが、今回はメソッドやプロパティが増えていたのでFusion360
ウィンドウ上の座標値が取得できました。

#FusionAPI_python
#Author-kantoku
#Description-MouseMoveTest
import adsk.core, traceback

_app = None
_ui  = None
_inputs  = None
_handlers = []

#このコマンドのイベント・ダイアログ作成
class MyCommandCreatedHandler(adsk.core.CommandCreatedEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            global _inputs, _handlers
            cmd = adsk.core.Command.cast(args.command)

            onDestroy = MyCommandDestroyHandler()
            cmd.destroy.add(onDestroy)
            _handlers.append(onDestroy)

            onMouseMove = MyMouseMoveHandler()
            cmd.mouseMove.add(onMouseMove)
            _handlers.append(onMouseMove)

            _inputs = cmd.commandInputs
            
            _inputs.addTextBoxCommandInput('Vp_Pos', 'Fusion360画面上の座標値', '-', 1, True)
            _inputs.addTextBoxCommandInput('Sc_Pos', 'ディスプレイ上の座標値', '-', 1, True)
        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)
        
        global _ui, _inputs
        vppos = eventArgs.viewportPosition
        ui_vp = _inputs.itemById('Vp_Pos')
        ui_vp.text = "x:[%d] y:[%d]"%(vppos.x, vppos.y)
        
        scrpos = eventArgs.viewport.viewToScreen(vppos)
        ui_sc = _inputs.itemById('Sc_Pos')
        ui_sc.text = "x:[%d] y:[%d]"%(scrpos.x, scrpos.y)
        
def run(context):
    try:
        global _app, _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)
        
        cmdDef.execute()

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

MouseMoveイベントからダイアログのテキストに座標値を書き込んでるのですが、
どうやったらダイアログを取得できるのだろう?と悩んだ末、[_inputs](ダイアログ自体)
のスコープを大きくするぐらいしか思いつかなかったのですが、前回の
コードを見たら・・・同じようにしてました。良いのか不安。

本当は、3Dの座標値が欲しかったのですが、上手くいきませんでした。
Help
こちらのViewportオブジェクトに 「viewToModelSpace」メソッドがあるのですが
例外にも引っかからないし…。
画面の奥行きに対しての座標値が定まらないので、無理なのはわかっているのですが。
cameraオブジェクトから計算したりするのかな?

DMUスペースアナリシスのセッション

「DMUスペースアナリシスのセッションを利用して、多くの断面を取得したい」
と御相談を頂きました。
が、当方にはDMUスペースアナリシスのライセンスが無い為、手も足も出ないのが
本音なのですが、過去にこちらを試した事があったため
出来る限りのことは記載しておきます。
技術的なオブジェクト?1 - C#ATIA

こんな感じのコードを作りました。

'vba
'DMUスペースアナリシスのセッションのテスト

Sub CATMain()
    'プロダクト
    Dim Prod As Product
    Set Prod = CATIA.ActiveDocument.Product
    
    'セクションコレクション
    Dim Sects As Object 'Sections
    Set Sects = Prod.GetTechnologicalObject("Sections")
    
    'セクション追加
    Call Sects.Add
    Dim Sect As Object 'Section
    Set Sect = Sects.Item(Sects.Count)
    
    'モード変更
    '0-catSectionBehaviorManual
    '1-catSectionBehaviorAutomatic
    '2-catSectionBehaviorFreeze
    Sect.Behavior = 1
    
    '0-without clipping  1-clipping
    Sect.CutMode = 1
    
    'マトリックス
    Dim Mat(11) As Variant ' Double
    Call Sect.GetPosition(Mat)
    
    Stop
    
    'マトリックス変更
    Mat(11) = Mat(11) + 1#
    Call Sect.SetPosition(Mat)

    'エクスポート
    '何処に何をエクスポートしているのか不明
    'Call Sec.Export

    Stop
End Sub

このマクロを実行すると、ライセンスが無いにも関わらずTree部分に
セクションが残ります。(使い道は無いのですが)
f:id:kandennti:20180516161755p:plain

Exportが全くの謎で、ライセンスがあれば可能だと思うのですが
手動操作も良くわかっていないため、この辺が限界です。

SetPositionで断面位置調節し、Exportをジャンジャン行えば良いの
だろうとは思うのですが・・・。