C#ATIA

↑タイトル詐欺 主にCATIA V5 の VBA

PowerMill2018

フォーラムではチラチラ名前が出てましたが、"What’s new" なサイトが出来てました。

PowerMill 2018 | New Features | Autodesk

リンク先がスカスカなんですが、動画は見れました。

"Ribbon interface" になるのは別に構わないのですが、こちらの動画の16秒辺りに出てくる
ツールパスコネクターダイアログの異常な大きさを何とかして欲しい。
(一度閉じないと、修正後の状態が見れません・・・)

"3D offset with center-line" 確かに他のCAMでも中心部に指定ピッチ以上2倍以下の
部分が残る場合が多いです。 外→内でこれが出来るのであれば良いかも。

"Stock simulation" PowerMillには幾つかシミュレーションのタイプがあるのですが、
そのうちのViewMillと言うシミュレーションのお話。
実は2017まで、シミュレーションを始めた向きから回転させる事が出来ないと言う
今時ありえない仕様だったのですが、ようやく回転させられるように
なるんですね。 ・・・使わない気がしますが。


動画を見る限り後は関係ないかな・・・。
旋盤も、5軸も、複合機も、インデックステーブルも、ユニバーサルヘッドも無いので。

コンテキストメニューからフォルダを展開する

PowerMillには僕の知る限り、古いバージョンからフォルダの機能があります。
このフォルダなのですが、WinなExplorer(ディレクトリ)とはちょっと挙動が
異なり、何となく要望があって後から付け加えた機能にも感じます。

もちろんフォルダ機能が無ければ、Treeが長すぎて扱いにくくなる為
活用しています。(社内では僕だけですが・・・)

このフォルダを展開したり縮小したりが・・・・まとめて出来ない!
そう、CATIAのこんな感じの機能が欲しいんです。
f:id:kandennti:20170419184259p:plain
(CATIAもここにあるので、案外使わないのですが)


こちらのすごいマクロを参考に作ってみました。
(正確には、ほぼパクリ)
Solved: Create macro to pick folder and activate it - Autodesk Community


まず、実際にフォルダの展開縮小を行うマクロです。
(TreeExpansion.mac としておきます)

//PMill_Macro
//TreeExpansion.mac

function main(string FolderType, int Level) {
	string list ValidFolderNames={'ncprogram','toolpath','tool','boundary','pattern','featureset','featuregroup','workplane','model','stockmodel'}
	IF not member($ValidFolderNames,lcase($FolderType)) {
		MESSAGE ERROR '不適切なフォルダ名です!'
		RETURN
	}	
	string list Folders = get_folders($FolderType)
	IF (size($Folders) == 0) {
		RETURN
	}

	$Folders=reverse($Folders)
	string cmd = 'EXPLORER SELECT $FolderType ROOT'
	DoCommand $cmd

	//全部閉じる
	if $Level == 0 {
		DEBUG EXPLORER KEY LEFT
		RETURN
	}
   
	DEBUG EXPLORER KEY RIGHT_RECURSIVE
	
	//全部開く
	if $Level < 0 {
		RETURN
	}
	
   foreach ff in folders {
      EXPLORER SELECT FOLDER $ff NEW
      DEBUG EXPLORER KEY LEFT
   } 
   
	//1レベル
 	if $Level == 1 {
		RETURN
	}  
   
	//nレベル
	string list Lv_n_Fols = {}
	foreach ff in folders {
		string list f=tokens($ff,'\')
		IF (size($f) == ($Level + 1)) {
			int dmy = add_last($Lv_n_Fols, dirname($ff))
		}
	} 
	
 	if size($Lv_n_Fols) == 0 {
		//指定レベルまでフォルダなし-全展開
		string cmd = 'EXPLORER SELECT $FolderType ROOT'
		DoCommand $cmd
		DEBUG EXPLORER KEY RIGHT_RECURSIVE
		RETURN
	} 
	
	foreach ff in Lv_n_Fols {
		EXPLORER SELECT FOLDER $ff NEW
		DEBUG EXPLORER KEY RIGHT
	} 	
}

念のため、このマクロ単体では動きません。

CATIAの様にメニューからの呼び出しが面倒な為、マクロの呼び出しはコンテキストメニューから
行いたいです。 以前行ったこちらの様に。
工具コンテキストメニューから工具変更 - C#ATIA


その為、toolpath.XML に追記します。
(この辺の方法は、Helpのカスタムメニュー辺りに記載されています)

<?xml version="1.0"  encoding="utf-8" ?>

<menupage>
	<menupage label="ツリー展開">
		<button label="全て縮小" command='MACRO all\TreeExpansion.mac "toolpath" 0' />	
		<spacer/>
		<button label="1次展開" command='MACRO all\TreeExpansion.mac "toolpath" 1' />
		<button label="2次展開" command='MACRO all\TreeExpansion.mac "toolpath" 2' />
		<button label="全て展開" command='MACRO all\TreeExpansion.mac "toolpath" -1' />
	</menupage>
	
	・・・

</menupage>

実際に設定した上での操作はこんな感じです。

個人的には楽になりそうです。
が、もうちょっと操作性を良くしたいんですけど、設定ファイルを編集する
必要性が有りそうなので、迷い中。

GSMGetObjectFromReference

COEにこんな記載が
http://www.coe.org/p/fo/st/thread=29679

リファレンスからオブジェクトを取得する関数。
使わないので忘れていたのですが、利用価値が無いわけじゃ
無いと思ってます。

ドキュメントに記載されていないので、忘れるわけです・・・。
と言う理由での覚書。

アクティブなブロックを未計算ツールパスに反映させる2

雛形を流用するために作ったこちらのマクロ
アクティブなブロックを未計算ツールパスに反映させる - C#ATIA


制限的な部分が有るものの、一応機能していたので使っていたのですが、
処理が地味に遅いので・・・。

何か方法が有るのではないかな? と思っていたのですが、どの様に
すれば良いのか? 全く手掛かりが有りませんでした。

フォーラムをボサッと眺めていたら、手動で行うこの操作が大きなヒントになりました。
Solved: Copy block to other toolpaths - Autodesk Community
こんな方法知らなかったです。

又、以前のマクロでは不満だった以下の部分も修正しました。
・任意の未計算ツールパスを選択可能に
・ブロックのタイプを全て可能に
・作業平面も反映
・安全領域も反映
又、こちらも必要です。
"group" フォルダは犠牲にした、プルダウンリストライブラリ - C#ATIA

//pm2017 macro
//アクティブなブロック・作業平面・安全領域を反映
//using downmenu.inc

function main() {
	//未計算ツールパス取得
	string filter = 'Computed == 0'
	string list paths =  extract(filter(folder('toolpath'), filter), 'name') 
	if is_empty(paths)  {
		message wran  '未計算ツールパスが見つかりませんでした'
		macro abort
	}
	
	//ユーザー選択
	string msg = '計算するツールパスを選択してください'
	call Exec_DownMenu($paths, $msg, 1, $paths) 	
	
	//バッチ処理
	call Msgoff()
	call Sw_Start()
	foreach path in $paths {
		string fullpath = pathname('toolpath', $path)
		EXPLORER SELECT Toolpath $fullpath NEW
		EDIT PAR SELECTED block
		EDIT PAR SELECTED Workplane
		EDIT PAR SELECTED Rapid
	}
	call Msgon()
	call Sw_GetTime()
	
	//終了
	message info  'Done'		
}

function Msgoff() {
	graphics lock
	dialogs message off
	dialogs error off
}

function Msgon() {
	graphics unlock
	dialogs message on
	dialogs error on
}

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

function Sw_GetTime() {
	CLOCK OFF QUIT
	CLOCK PRINT QUIT
}

include downmenu.inc

速度Upした大きな要因は、以前のものでは変更するツールパスを毎回アクティブに
していたのですが、今回のものは単に選択しただけの状態で、修正を
反映している事だろうと思われます。

こちらが以前のもの。 処理時間自体は4秒ほど。


こちらが今回のもの。 0.8秒ぐらいです。


動画中では安全領域が修正されていない(工具先端位置)状態なのですが、
実際に計算させると、修正が反映されています。
(左:計算前  右:計算後)
f:id:kandennti:20170417183423p:plain

今回のデータでは3秒程しか短縮していませんが、実際の業務では
もっと多くの工程があるため、より多くの効果を体感します。

他の作業と平行して行うほど時間がかかる訳でもなく、瞬時に処理が
終わるわけでもなく、あくまで "処理が地味に遅い" だったため
若干ストレス感じていました。
時間的な効果より、気持ちの面での効果のほうが大きいのが本音です。

未計算ツールパスをまとめてバッチ処理する

何となく方向性が定まらないのですが、これは使って行きそうなので
公開しておきます。

こちらの自作プルダウンリストのライブラリを利用し、選択された未計算ツールパスを
バッチ処理させるマクロです。 その為こちらが必要です。
"group" フォルダは犠牲にした、プルダウンリストライブラリ - C#ATIA

//pm2017 macro
//ツールパスバッチ ver0.0.2
//using downmenu.inc

function main() {
	//未計算ツールパス取得
	string filter = 'Computed == 0 and Batch == 1'
	string list paths =  extract(filter(folder('toolpath'), filter), 'name') 
	if is_empty(paths)  {
		message wran  '未計算ツールパスが見つかりませんでした'
		macro abort
	}		
	//ユーザー選択
	string msg = '計算するツールパスを選択してください'
	call Exec_DownMenu($paths, $msg, 1, $paths) 
	
	//バッチタイプ選択
	bool cal_type = 0
	$cal_type = QUERY 'バックグランド処理で行いますか?'

	//バッチ処理
	call Msgoff()
	call Sw_Start()
	foreach path in $paths {
		if $cal_type {
			TOOLPATH $path QUEUE
		} else {
			ACTIVATE TOOLPATH  $path
			TOOLPATH $path CALCULATE
		}
	}
	call Msgon()
	call Sw_GetTime()
	//終了
	message info  'Done'	
}

function Msgoff() {
	graphics lock
	dialogs message off
	dialogs error off
}

function Msgon() {
	graphics unlock
	dialogs message on
	dialogs error on
}

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

function Sw_GetTime() {
	CLOCK OFF QUIT
	CLOCK PRINT QUIT
}

include downmenu.inc

開発時に利用したかった為、実行時間をコマンドエコーに表示させていますが
特に悪さをするわけでない為、そのままにしておきます。

実際に実行した感じはこちらです。

動画時間の都合上、1個づつしか試していませんが、
実際は複数選択可能です。

バックグランド処理が遅いので、選択してしては無かったのですが
利用したいときも有ったので選択可能にしてみました。



あぁそうだ、このマクロとは無関係なお話です。
何時も、AutodeskさんのScreencastを利用して動画を作っている
のですが、Screencastはアクティブなソフトのみをキャプチャしてくれます。
操作性が落ちるのですが、出来るだけウィンドウを小さくして
記録した方が、何の操作を行っているのか? が、わかりやすいため
そのようにしています。(他の方もそうして欲しい・・・)

実は、以前YoutubeでCATIAのTips動画を100本ぐらいUpしていた方が
そのようにしており、非常に見やすかったのでそのように
心掛けています。(それらの動画はもう無いです)

選択した円弧の長さを表示2

こちらの続きです。
選択した円弧の長さを表示1 - C#ATIA

もう一つ方法があり、パラメータと式を利用した方法です。

'vba  test_Circle_Length_Formula
'using-'KCL0.0.10'
'円弧の長さを表示-式利用

Option Explicit

Sub CATMain()
    'ドキュメントのチェック
    If Not CanExecute("PartDocument") Then Exit Sub
    
    '選択
    Dim msg$: msg = "円弧を選択して下さい : ESCキー 終了"
    Dim Elem As SelectedElement
    Dim Pt As Part
    Dim Ref As Reference
    Do
        Set Elem = KCL.SelectElement(msg, "HybridShape")
        If KCL.IsNothing(Elem) Then Exit Do
        Set Pt = Elem.Document.Part
        Set Ref = Elem.Reference
        If IsCircle(Ref, Pt.HybridShapeFactory) Then
            MsgBox "円弧長さは" & GetLength_Formula(Ref, Pt) & "mmです"
        Else
            MsgBox "円弧を選択してください"
        End If
    Loop
End Sub

Private Function GetLength_Formula#(ByVal Ref As Reference, ByVal Pt As Part)
    'パラメータ作成
    Dim length As length
    Set length = Pt.Parameters.CreateDimension("", "LENGTH", 0#)

    '式を作成する為の名前を取得
    Dim CorrectName$: CorrectName = Pt.Parameters.GetNameToUseInRelation(Ref)
    
    '式作成
    Dim formula As formula
    Set formula = Pt.Relations.CreateFormula("AutomaticNaming", "", length, "length(" & CorrectName & " ) ")
    
    '長さ取得
    GetLength_Formula = length.Value
    
    '要らない物削除
    Dim Sel As Selection
    Set Sel = Pt.Parent.Selection
    With Sel
        .Clear
        .Add formula
        .Add length
        .Delete
    End With
End Function

'円弧の判断
Private Function IsCircle(ByVal Ref As Reference, ByVal Fact As HybridShapeFactory) As Boolean
    Dim GeoType&: GeoType = Fact.GetGeometricalFeatureType(Ref)
    'AutomationManualの記述が間違えやすいが、
    '4-Circle になる
    IsCircle = IIf(GeoType = 4, True, False)
End Function

こちらは、一時的に長さのパラメータと式を作成。 値を取得後、パラメータと式を削除しており、
使い勝手としては悪い上、恐らく遅いです。

このサンプルをUpしたのは、これ自体が目的ではないんです。
僕にしてはコメント多めに入れた "GetLength_Formula" 関数をご覧下さい。

手動で式を作る際には、こんな感じになります。
f:id:kandennti:20170412181108p:plain
実は赤印部分が問題なんです。
オブジェクトの名前やリファレンスのディスプレイネームでは "円.1" としか取得出来ませんが、
式として(上記画像の場合)必要なのは、"`形状セット.1\円.1`" なんです。
しかも前後に記載されているシングルクォーテーションの有無は、オプションの設定で
変更が可能な為、非常にややこしいのが本音です。

その為に、式に必要な名称を取得する関数が用意されています。

    '式を作成する為の名前を取得
    Dim CorrectName$: CorrectName = Pt.Parameters.GetNameToUseInRelation(Ref)

実はかなり以前に、こちらで知ったんですが・・・
Developing proper names to use in product relations | CATIA V5 Automation
今回は式に利用していますが、"どこの形状セット等に所属している要素か?"
と言う利用方法もあるかと思います。


又、こちらは式を作成している部分です。

    '式作成
    Dim formula As formula
    Set formula = Pt.Relations.CreateFormula("AutomaticNaming", "", length, "length(" & CorrectName & " ) ")

式を作成する際、第一引数に必ず式の名前を文字列として渡す必要があります。
試したところ、重複した名前でもエラーにはならないようですが、後々の作業で
同じ式が存在したままだと混乱するかも知れません。
この様な場合 "AutomaticNaming" を第一引数にすることで、CATIA自身が自動的な
名前を付けるようになっているようです。
・・・と書いたのですが、長さ0の文字列を渡しても同じでした。

CATIAのマクロで、インスタンスを作成する際に名前を引数で渡さなければならないものが
幾つかあるようなのですが、恐らくそのような場合に利用できるかと思います。

説明していませんが、こちらのサンプルでもDrawのディテールシートを新規に作成する際
"AutomaticNaming" を利用しています。
指定した2D要素を、指定した原点位置でコピペする - C#ATIA

選択した円弧の長さを表示1

ちょっと相談?を頂いたので、久々にCATIAのマクロを書いてみました。

選択した3D円弧の長さを表示するだけのものです。
極端な話、こちらの物を流用しただけです。
線を選択しつつ、合計長さを表示する - C#ATIA

'vba  test_Circle_Length
'using-'KCL0.0.10'
'円弧の長さを表示

Option Explicit

Sub CATMain()
    'ドキュメントのチェック
    If Not CanExecute("PartDocument") Then Exit Sub
    
    '選択
    Dim msg$: msg = "円弧を選択して下さい : ESCキー 終了"
    Dim Elem As SelectedElement
    Dim Pt As Part
    Dim Ref As Reference
    Do
        Set Elem = KCL.SelectElement(msg, "HybridShape")
        If KCL.IsNothing(Elem) Then Exit Do
        Set Pt = Elem.Document.Part
        Set Ref = Elem.Reference
        If IsCircle(Ref, Pt.HybridShapeFactory) Then
            MsgBox "円弧長さは" & GetLength(Ref, Pt) & "mmです"
        Else
            MsgBox "円弧を選択してください"
        End If
    Loop
End Sub

'長さの取得
Private Function GetLength#(ByVal Ref As Reference, ByVal Pt As Part)
    GetLength = Pt.Parent.GetWorkbench("SPAWorkbench").GetMeasurable(Ref).Length
End Function

'円弧の判断
Private Function IsCircle(ByVal Ref As Reference, ByVal Fact As HybridShapeFactory) As Boolean
    Dim GeoType&: GeoType = Fact.GetGeometricalFeatureType(Ref)
    'AutomationManualの記述が間違えやすいが、
    '4-Circle になる
    IsCircle = IIf(GeoType = 4, True, False)
End Function

イロイロな事を忘れかけていました。

SelectElement2を利用する際のフィルターなのですが、今回や流用元では
"HybridShape" を利用しているのですが、選択する為の自由度と言いますか
柔軟性は "Edge" の方が良いのです。

が、その先の処理が思うように出来なかった為(リファレンスのタイプが異なる)
前回も "HybridShape" にしたんじゃないのかな? と薄っすらな記憶・・・。
CreateReferenceFromBRepNameが上手く取得出来れば、Edge" を利用したかった
のですが。