読者です 読者をやめる 読者になる 読者になる

C#ATIA

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

円筒的矢視図を作りたい

CATIA_V5

久々にCATIAネタです。
少し前に業務で行った、円筒形部品の図面を描く際の悩みです。
タイトルでは "円筒的矢視図" と書きましたが、正しい名称すらよくわかって
おりません。(展開図と表記すると望んでいない答えが返ってくるもので)


本来円筒形部品のお話ですが、簡略化する為、真っ二つにした状態で
進めます。

こんな感じの部品の図面化をしたいのですが、
f:id:kandennti:20170328191210p:plain

手抜きですが、こんな図面ならそれ程苦にはならないです。
f:id:kandennti:20170328191215p:plain

実際に欲しいのは、外側の形状だけで構わないので、こんな感じの
図面なんです。(テキトーに描いてます)
f:id:kandennti:20170328191224p:plain
Y軸は単位が長さで、X軸の単位は角度で欲しいんです。
(逆でも構いませんが・・・)


高価なライセンスが無いのですが、こちらの手法を利用すれば
ゴールまでたどり着けそうなものが、ひょっとしたらあるのかな?
とは、薄々感じています。
ライセンスの無いコマンドを使用する - C#ATIA

とりあえず面倒なのですが、展開コマンドを主要な面に対して2回
行った結果がこちら。
f:id:kandennti:20170328191245p:plain
プレスの展開図を作成するには良いのですが、ちょっと望んでいる
結果にはなりません。

続いて、シェイプモーフィングコマンド。 正直、このコマンドの使い方が
イマイチわかっていないのですが、ターゲットとなる緑のラインを2本作成し
赤のエッジを基準にさせてみました。
f:id:kandennti:20170328191250p:plain

結果がこちら。
f:id:kandennti:20170328191255p:plain
一見良さそうに見えたのですが、やっぱり望んでいるものとは
ちょっと違うんです。

緑のラインの長さが違うからかな? と思い水色のターゲットを作成
しましたが、やっぱり望んだものとは異なります。
f:id:kandennti:20170328191301p:plain


イメージとしては、形状より外側にガイドになる円弧を描き、
ガイド上から中心軸に向かってカメラ(黄色矢印)を設置し、グルッと
ガイド上を走査する(緑色矢印)ような状態で欲しいんです。
f:id:kandennti:20170328191308p:plain

そこで、ガイドになる円弧を押し出し、この押し出し面に対し
エッジをチマチマ投影(まとめて行うとおかしくなる)。
この投影されたラインを平面に展開できれば良いのですが、
その為のコマンドが存在するものかどうかが、わからないんです。
f:id:kandennti:20170328191314p:plain
これの逆、平面にデザインしたラインを曲面に配置するディベロップコマンドの
存在は知っているのですが、このコマンドでは逆は出来ないんです。

ワイヤーで処理するのを諦め、さっきの投影したラインからスイープで
ガイド面(薄いピンク)に直角な面(紫)を作成し、ラップサーフェスコマンドで
作ったものが水色の面。
f:id:kandennti:20170328191320p:plain

これを平面的に見ると、かなり望んでいるものになります。
f:id:kandennti:20170328191328p:plain
惜しいのは、Φ10の閉じた円弧が楕円になってしまうのですが、
まぁこれぐらいなら2D側で修正しても良いかな?とは感じてます。
(恐らく投影時の処理が望んでいない状態を生み出している)


この方法でも結構手間な上、曲線は正しくないものが出来そうな
予感はしています。(手間な部分はマクロ化してしまっても良いのですが)

この話は、サポートにも相談したのですが上手く伝わらなかったのか、
やっぱりシートメタル的な展開図の機能を紹介されてしまいます。

CATIAに限らず、この様な機能を持っているソフト等をご存知の方が
いらっしゃいましたら、教えて頂けると助かります。

・最終的に欲しいのは2Dなので、サーフェス等では無くても構いません
・CATIAに拘りません
・全てを一発で処理する必要は無く、部分的なマクロでも十分です

平面的な座標軸の片側が長さで、もう片方が角度で表現出来ていれば
良いので、円筒座標系があれば良いのですが、CATIAには直交座標系
しか無さそうです。

そんなに難しい事でも無さそうなのですが、CATIAのマクロでは
3Dラインから得られる情報がほぼ無い為、お手上げです。
Fusion360のスプリクトでは3Dラインから情報はかなり得られるのですが、
そこまで作り上げる能力が僕には無い為、こちらもお手上げです。

結構需要があるんじゃないかな?

工具コンテキストメニューから工具変更

PowerMill

計算済みツールパスの工具を変更したい時があります。 かなり、頻繁に・・・。
手動で行うと結構手間で、正直モチベーションが落ちまくります。
手順はこんな感じです。
・任意のツールパスをアクティブ
・変更したい工具をアクティブ
・ツールパスのコンテキストメニューで '工具変更' (しかもメニュー位置が深い・・・)

実際の操作はこんな感じです。


これを楽しようと思いマクロを作成したのですが、PowerMillのマクロの
呼び出し方が複数有り、今回は操作的に直感的なので工具のコンテキストメニューを
利用しての呼び出しにしました。
この呼び出し方法、実は知りませんでした。(Helpには記載されています)
こちらが非常に参考になりました。
Solved: Create macro to pick folder and activate it - Autodesk Community


前回のプルダウンリストを利用して、複数のツールパスに対して工具変更が出来るように
しています。(但し、スクエア・ボール・ラジアス・テーパーボールエンドミルのみです。)

マクロ本体です。

//PMill_Macro
//ReplaceTool.mac
//Treeの指定した工具のコンテキストメニューから工具交換

function main(string toolname) {
	//選択工具
	entity act = entity('tool', $toolname)
	
	//交換可能リスト
	string list paths = {}
	call Get_PathList($act, $paths) 
	if is_empty($paths) {
		message error  '交換可能なツールパスがありません!!'
		return
	}
	
	//ユーザー確認
	string msg = '[' + $act.name + ']' + 'に工具交換するツールパスを選択してください'
	call Exec_DownMenu($paths, $msg, 1, $paths)
	
	//工具交換
	call Set_ActTool($act, $paths)
	
	//終了
	message info  'Done'
}

//工具交換
function Set_ActTool(entity ActTool, string list Lst) {
	call Exec_Cmd('ACTIVATE TOOL "' + $ActTool.name + '"')
	foreach path in $Lst {
		call Exec_Cmd('EDIT TOOLPATH "' + $path + '" REPLACE_TOOL ;')
	}	
}

//交換可能リスト取得
function Get_PathList(entity ActTool, output string list OutLst) {
	string list lst = {}
	bool geoeql = 0
	foreach path in folder('toolpath') {
		call ToolNose_Equal($path.tool, $ActTool, $geoeql)
		if $geoeql {
			int dmy = add_last($lst, $path.name)
		}
	}
	$OutLst = $lst
}

//工具先端一致判断
function ToolNose_Equal(entity T1, entity T2, output bool OutBool) {
	$OutBool = 0
	string T1_type = $T1.type
	string T2_type = $T2.type
	
	if $T1_type != $T2_type {
		return
	}
	
	if $T1.Diameter != $T2.Diameter {
		return
	}
	
	Switch T1_type {
		case 'end_mill'
			$OutBool = 1
			return
			break
		case 'ball_nosed'
			$OutBool = 1
			return
			break
		case 'tip_radiused'
			if $T1.TipRadius == $T2.TipRadius {
				$OutBool = 1
			}
			return
			break				
		case 'taper_spherical'
			if $T1.TipRadius == $T2.TipRadius and $T1.TaperAngle == $T2.TaperAngle {
				$OutBool = 1
			}
			return
			break				
	}
}

//コマンド
function Exec_Cmd(string cmd) {
	docommand $cmd
}

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

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

include downmenu.inc

最後のインクルードは、前回のプルダウンリストのライブラリです。

続いて、工具のコンテキストメニューに追加する為の "tool.XML" です。
既に他で利用されている場合は、buttonタグ部分を追記すればOKです。
又、今まで利用していない場合は、環境変数の追加や指定されたフォルダを
作成する必要があるため、Helpを参考にすると良いかと思います。
(上記のマクロは同一フォルダ内に配置しておく必要が有ります)

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

<menupage>

<button label="工具変更"
command='MACRO ReplaceTool.mac "%s"'
/>

</menupage>


実際に利用した感じはこちら。

桁違いに楽。

"group" フォルダは犠牲にした、プルダウンリストライブラリ

PowerMill

相変わらず、PowerMillが使いこなせていない・・・。

方向性を定める為、イロイロと試していた為マクロの製作も止めていました。
少しづつ迷いが取れきたので、少しマクロで楽をしたいところ。

使い回しが出来そうなので、"group" フォルダは犠牲にしたプルダウンリストを
ライブラリ化しました。 こちらのものに近いものです。
アクティブなブロックを未計算ツールパスに反映させる - C#ATIA

//PMill_Macro
//downmenu.inc

//ダウンメニュー
//pram  :Lst-選択肢リスト
//pram  :Msg-メッセージ
//pram  :AbortFg-未選択時の処理 0-空を返す 1-終了
//return:OutLst-選択されたリスト
function Exec_DownMenu(string list Lst, string Msg, bool  AbortFg, output string list OutLst) {
	$OutLst = {}
	string allword = '全て'
	
	//実行確認
	call Can_Exec()
	
	//先頭に全てを追記
	int dmy = add_first($Lst, $allword)
	
	//ダミー
	call Create_DmyGroup($Lst) 
	
	//ユーザー選択
	entity list grps =  input entity multiple group $Msg
	DELETE GROUP ALL
	EDIT RECYCLER DELETE Group ALL
	if is_empty(grps) {
		if $AbortFg==1 {
			macro abort
		} else {
			return
		}
	}
	string list sels = extract(grps , 'name')
	
	//選択要素
	if $sels[0] == $allword {
		string tmp = remove_first($Lst)
		$OutLst = $Lst
	} else {
		$OutLst = $sels	
	}
	return
}

//選択用ダミー作成
function Create_DmyGroup(string list Lst) {
	foreach txt in $Lst {
		CREATE GROUP ;
		RENAME Group "1" $txt
	}
}

//条件確認
function Can_Exec() {
	if not (is_empty(folder('group'))) {
		string msg = 'グループフォルダを利用する為、グループフォルダをクリアします。' + crlf + '宜しいですか?'
		bool yn = 0
		$yn = QUERY $msg
		if not $yn {
			macro abort	
		}
		DELETE GROUP ALL
	}
}

これ自体は特に何かが出来るものでは無いため、説明は割愛。
使用例はそのうちUpします。(出来ると良いな・・・)

何処で販売しているのか見つけられない

雑談

何となくこんな記事を見つけました。

キヤノンITS、SOLIDWORKSの“かゆいところ”に手が届くツール61種を販売 - MONOist(モノイスト)

よく見ていませんが、そのうちCATIAのマクロのネタに出来るかも知れない。

ツールパスバッチ処理 時間測定

PowerMill

PowerMillは、ツールパス・バウンダリの計算はGUIが操作出来なくなる
以来からあるバッチ処理と、バックグランドで行うバッチ処理の二つの
方法があるのですが、何となく体感的にバックグランドの処理が
遅いように感じてます。

同一処理での時間測定を異なるバッチ処理方法で測定したかったの
ですが、バックグランド処理の時間測定方法がわからず・・・。
(知っている方教えて頂けると助かります)

Windowsに標準で入っているパフォーマンスモニターでCPUの負荷を確認して
みると・・・ バックグランドは1.5~2倍ぐらいの処理時間がかかってます。



又、以前見つけた(マニュアルにも記載有り)グラフィックスのロックですが、
どれ程の効果があるものか試す為、こんなマクロを作ってみました。

function main() {
	DIALOGS MESSAGE OFF
	DIALOGS ERROR OFF
	ECHO OFF DCPDEBUG UNTRACE COMMAND ACCEPT
	
	call ResetToolpath()
	graphics unlock
	print = "-- basic batch graphics_unlock --"
	call Sw_Start()
	BATCH PROCESS
	call Sw_GetTime()
	
	call ResetToolpath()
	graphics lock
	print = "-- basic batch graphics_lock --"
	call Sw_Start()
	BATCH PROCESS
	call Sw_GetTime()
	graphics unlock
	
	DIALOGS MESSAGE ON
	DIALOGS ERROR ON
	ECHO ON DCPDEBUG TRACE COMMAND ACCEPT	
}

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

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

function ResetToolpath() {
	INVALIDATE TOOLPATH ALL
	Yes
	INVALIDATE BOUNDARY ALL
	Yes
}

既存のプロジェクトのツールパス・バウンダリを全て無効化し、
再度全てをバッチ処理させるだけのものです。

結果は・・・殆ど変わらないw

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

PowerMill

恐らくどの3DCAMでも、類似した工程を製作する際は
予め作成しておいた雛形を流用するのだろうと思います。

PowerMillにもテンプレートオブジェクトと言う機能が有り、非常に
便利なのですが、ちょっと困る部分もあったりします。

テンプレートを呼び出した際、各ツールパスが切削領域を設定する
ブロックが記録した際サイズのままになってしまいます。
これを一つずつ修正するなんて、僕には有り得ないお話。

なので、アクティブなブロックを未計算ツールパスに反映させる
マクロを作ってみました。

//pm2017 macro sample_Active_Block_Copy.mac
//アクティブなブロックを未計算ツールパスに反映させる

function main() {
	//確認
	string msg = ''
	call Can_Exec() 
	
	//ブロックタイプ
	if block.type != "box"  {
		message wran  'ボックスタイプのブロックしか対応出来ません!!'
		macro abort
	}
	
	//ブロックサイズ
	real list Limits = {}
	call Get_BlockSize($Limits)
	string cmd = ''
	call Get_CmdString($Limits, $cmd)
	
	//未計算パス
	string list paths = extract(filter(folder('toolpath'), 'Computed == 0'), 'Name')
	if is_empty(paths)  {
		message wran  '未計算のツールパスが見つかりませんでした'
		macro abort
	}
	
 	//ユーザー選択
	call Lst_ToString($paths, crlf, $msg) 
	$msg = '以下のツールパス全て、ブロックを修正しますか?' + crlf + $msg
	bool yn = 0
	$yn = QUERY $msg
	if not $yn {
		//選択用ダミー作成
		call Create_DmyGroup($paths)
		if is_empty(folder('group')) {
			message error  'エラーです。中止します(エラー_Group)'
			macro abort
		}		
	
		$msg = '現在のブロックを反映する' + crlf + 'ツールパスを選択してください' 
		entity list grps =  input entity multiple group $msg
		DELETE GROUP ALL
		if is_empty(grps) {
			macro abort
		}	
		$paths = extract(grps , 'name')
	}
	
	//ブロックコピー
	call DialogOff()
	call Set_BlockSize($paths, $cmd)
	call DialogOn()
}

//コード取得
function Get_CmdString(real list Limits, output string OutTxt) {
	string txt = ''
	$txt =  $txt + 'EDIT BLOCK XMIN "' + string($Limits[0]) + '"' + crlf
	$txt =  $txt + 'EDIT BLOCK XMAX "' + string($Limits[1]) + '"' + crlf
	$txt =  $txt + 'EDIT BLOCK YMIN "' + string($Limits[2]) + '"' + crlf
	$txt =  $txt + 'EDIT BLOCK YMAX "' + string($Limits[3]) + '"' + crlf
	$txt =  $txt + 'EDIT BLOCK ZMIN "' + string($Limits[4]) + '"' + crlf
	$txt =  $txt + 'EDIT BLOCK ZMAX "' + string($Limits[5]) + '"' + crlf
	$OutTxt = $txt
}

//ブロックコピー
function Set_BlockSize(string list Lst, string Cmd) {
	foreach path in $Lst {
		ACTIVATE TOOLPATH $path
		EDIT BLOCK ALL UNLOCK
		EDIT BLOCKTYPE BOX
		EDIT BLOCK COORDINATE WORKPLANE
		call Exec_Cmd($cmd)
		EDIT BLOCK ALL LOCK
		EDIT TOOLPATH $path REAPPLYFROMGUI
	}
}

//コマンド
function Exec_Cmd(string cmd) {
	docommand $cmd
}

//ブロックサイズ取得
function Get_BlockSize(output real list OutLst) {
	real list lst = {}
	int dmy = 0
	real vlu = 0
	$dmy = add_last($lst, round(block.limits.xmin,4))
	$dmy = add_last($lst, round(block.limits.xmax,4))
	$dmy = add_last($lst, round(block.limits.ymin,4))
	$dmy = add_last($lst, round(block.limits.ymax,4))
	$dmy = add_last($lst, round(block.limits.zmin,4))
	$dmy = add_last($lst, round(block.limits.zmax,4))
	$OutLst = $lst
}

//選択用ダミー作成
function Create_DmyGroup(string list paths) {
	foreach txt in $paths {
		CREATE GROUP ;
		RENAME Group "1" $txt
	}
}

//条件確認
function Can_Exec() {
	if not (is_empty(folder('group'))) {
		string msg = 'グループフォルダをクリアします。' + crlf + '宜しいですか?'
		bool yn = 0
		$yn = QUERY $msg
		if not $yn {
			macro abort
		}
		DELETE GROUP ALL
	}
}

//ダイアログ類オン
function DialogOn() {
	GRAPHICS UNLOCK
	DIALOGS MESSAGE ON
	DIALOGS ERROR ON
	ECHO ON DCPDEBUG TRACE COMMAND ACCEPT
}

//ダイアログ類オフ
function DialogOff() {
	GRAPHICS LOCK
	DIALOGS MESSAGE OFF
	DIALOGS ERROR OFF
	ECHO OFF DCPDEBUG UNTRACE COMMAND ACCEPT
}

//リストから文字列
function Lst_ToString(string list Lst , string Delimiter , output string Outtxt) {
	string txt = ''
	foreach itm in $Lst {
		$txt = $txt + $itm + $Delimiter
	}
	int lng = length($txt) - length($Delimiter)
	$Outtxt = substring($txt , 0 , $lng)
	return
}

まずアクティブなブロックを決め(BOXタイプのみ)、マクロを実行すると
ブロックサイズを修正します。

実際に実行した動画はこちらです。

・・・何やっているか全くわからないと思います。

2回目にマクロを実行した際のプルダウンリストの動きは、前回の最後に
記載した方法で実現させています。
PowerMillマクロのダイアログ類 - C#ATIA
その為、"group" フォルダは犠牲にしています。

(ひょっとしたら全てを一度に直す機能が標準コマンドであるのかな?)

PowerMillマクロのダイアログ類

PowerMill

前回は、結局マニュアルに記載されていた関数のみでした。
今回こそは・・・、と思ったのですが、調べると今回も殆どがマニュアル
記載のものです。

PowerMillのマクロで処理した際、マクロユーザーに何らかのメッセージや選択を促す
ダイアログ類の覚書です。


〇エコーコマンド
どちらかと言うと、開発者用です。
VBAのイミディエイトウィンドウと同等なエコーコマンドへの出力です。
アクティブな工具名の出力です。

function main() {
	print = tool.name
}


〇message ~
OKボタンのみのダイアログです。

function main() {
	message info tool.name
	message warn tool.name
	message error tool.name
}


〇INFOBOX
これはマニュアルに記載されていないです。
ポスト処理やCADデータをインポートした際に現れるダイアログのようです。
messageダイアログより表現豊かで、これは表示されてもマクロの実行が
止まりませんでした。又、これはマクロから閉じる事も可能でした。

function main() {
	INFOBOX NEW "info box test"

	string txt = "HEADING STYLE : " + tool.name + crlf + crlf
	INFOBOX STYLE "HEADING"
	INFOBOX APPEND $txt

	$txt = "NORMAL STYLE : " + tool.name + crlf + crlf
	INFOBOX STYLE "NORMAL"
	INFOBOX APPEND  $txt

	$txt = "WARNING STYLE : " + to_xml(entity('Tool', tool.name))
	INFOBOX STYLE "WARNING"
	INFOBOX APPEND  $txt

	WAIT 3.0
	INFOBOX CLOSE
}

"WARNING STYLE : "の横のto_xml関数もマニュアルの記載が無く、パラメータをXMLフォーマットで
出力するようです。
WAIT関数もマニュアルの記載がありません。単位は秒のようです。
こちらのサンプルの方がイロイロと表現されています。
Delcam User Forum • View topic - Can you do images in a message box popup?


〇QUERY
'はい' 'いいえ' ボタンを持つダイアログです。

function main() {
	bool yn = 0
	string msg = ''
	$yn = QUERY 'このブログの記述は、信用出来ない?'
	if $yn {
		$msg = 'その通り!'
	} else {
		$msg = 'よく考えよう!'
	}
	message warn $msg
}


〇input
単純な入力用ダイアログです。
事前に受け取る変数に値を入力しておくと、デフォルトで設定されるようです。
(古いバージョンでは出来なかったような・・・)

function main() {
	int num = 23
	$num = input "何歳(数字で入力)"
	bool err = 0
	$err = error num
	string msg = ''
	if $err {
		$msg = '数字入力だって!!'
	} else {
		$msg = '多分、' + $num + '歳'
	}
	message warn $msg
}

上記のコードで文字を入力すると、通常は都合が悪く(int型に文字を代入)
エラーになるべきなのですが、PowerMillのマクロでは '0' が代入されてしまいます。
PowerMillのマクロでは例外処理が出来ないのですが、inputに関しては
上記のコードの方法でエラーを拾えるようです。


〇input entity ~
指定した組み込みフォルダ内のエンティティを選択肢としたセレクトボックスです。
inputでは、マクロユーザーの入力ミスに対してのチェックコードを用意する必要が
あると思いますが、こちらはその手間が省けるため、マクロの開発者・ユーザーの
負担が軽減できます。
事前に受け取る変数内に値を入れておけば、デフォルト値として表示されました。

function main() {
	string msg = "アクティブにする工具を選んでください" + crlf + "現在は " + tool.name
	string toolname = tool.name
	$toolname = input entity tool $msg
	activate tool $toolname
	message warn $toolname + " をアクティブツールにしました"
}

上記コードでは '工具フォルダ' から工具を選択させるようにしています。
f:id:kandennti:20170221191908p:plain


〇input entity multiple ~
input entity ~ は、プルダウンされたリストから1個しか選択出来ませんが、
こちらは複数選択が可能です。
事前に受け取る変数内に値を入れておいても、デフォルトでチェックが入った
状態にはなりませんでした。

function main() {
	string msg = "バックグランドで計算させるツールパスを選択してください" 
	entity list paths = input entity multiple toolpath $msg
	foreach path in $paths {
		INVALIDATE TOOLPATH $path.name
		EDIT TOOLPATH $path.name QUEUE
	}
	message info size($paths) + "個をバックグランドで計算登録しました"
}

上記のコードは、既に存在しているツールパスをプルダウンリストし、選択されたツールパスを
バックグランド計算に投げるコードです。(計算済みのものも強制的に計算させます)
f:id:kandennti:20170221191917p:plain


〇input choice
input entity multiple ~は組み込みフォルダ内の全てのエンティティが表示されて
しまいます。上記のコードの場合であれば、未計算のツールパスだけを選択肢
したいところです。 こちらは事前に処理しておいたリストを選択肢として
おくことが可能です。 リストの一番最初のものがデフォルト値となるようです。
戻り値はリストのインデックスです。

function main() {
	string list paths = extract(filter(folder('toolpath'), 'Computed == 0'), 'Name') 
	string msg = "バックグランドで計算させるツールパスを選択してください" 
	int idx = input choice $paths $msg
	string cmd = "EDIT TOOLPATH " + $paths[$idx] +" QUEUE"
	docommand $cmd
	message info $paths[$idx]  + "をバックグランドで計算登録しました"
}

上記のコードは、先日のfilter・extract関数で事前に未計算のツールパスのみを
探し出し、プルダウンリストとして表示させます。
f:id:kandennti:20170221191925p:plain
残念なのは、複数選択が出来ない事です。


フォーラムを見ても

//これはNGです
・・・
string list paths = extract(filter(folder('toolpath'), 'Computed == 0'), 'Name') 
string msg = "バックグランドで計算させるツールパスを選択してください" 
int idx = input choice multiple $paths $msg
・・・

の様に、リストの複数選択したいけど出来ないの? のような記載はありますが
どうも出来ないようです。
代案としては、どれか一つ組み込みフォルダを犠牲にして・・・と言う感じの
コードに僕はしてみましたけど。