C#ATIA

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

クリックした点の座標値を外部ファイルにエクスポート

こちらでコメントを頂いたので、リハビリがてら作ってみました。
Excelフォームボタンからマクロの起動 (未確認) - C#ATIA

'vba sample_ExpPointPos_ver0.0.1 by Kantoku
'選択した点の座標値をファイルにエクスポート
Option Explicit

'*** エクスポートするフォーマットを設定して下さい ***
'txt - スペース区切り
'csv - カンマ区切り
'xls - Excelに直接(要Excel起動)
Const ExpType = "csv"
'*********

Sub CATMain()
    'ドキュメントのチェック
    If Not CanExecute("PartDocument") Then Exit Sub
    
    'ドキュメント
    Dim Doc As PartDocument
    Set Doc = CATIA.ActiveDocument
    
    'ドキュメントパス
    Dim DocPath As Variant
    DocPath = GetDocDir(Doc)
    
    'excelのみ
    If ExpType = "xls" Then
        Dim Xlapp As Object
        Set Xlapp = GetExcel()
    End If
    
    '点選択
    Dim Filter As Variant
    Filter = Array("Point")
    
    Dim Msg As String
    Msg = "点/頂点を選択してください : [Esc]=キャンセル"
    
    Dim Data As Collection '取得データ格納用
    Set Data = GetPointInfo(Msg, Filter)
    
    If Data.Count < 1 Then End 'データ無し
    
    'エクスポート
    DocPath(1) = DocPath(1) & "_SelPoint"
    Dim ExpPath As String
    Select Case ExpType
        Case "txt"
            ExpPath = ExpTxt(DocPath, Data, " ", "txt")
        Case "csv"
            ExpPath = ExpTxt(DocPath, Data, ",", "csv")
        Case "xls"
            ExpPath = ExpXls(DocPath, Data, Xlapp)
    End Select
    
    Msg = ExpPath & vbNewLine & _
          CStr(Data.Count) & "個分の座標値をエクスポートしました"
    MsgBox Msg
End Sub

'エクスポート - excel
Private Function ExpXls(ByVal Path As Variant, ByVal Data As Collection, _
                        ByVal Xlapp As Object) As String
    Dim Wb As Object 'WookBook
    Set Wb = Xlapp.Workbooks.Add
    
    Dim Ws As Object 'WorkSheet
    Set Ws = Wb.ActiveSheet
    
    Dim I As Long, J As Long
    For I = 1 To Data.Count
        For J = 1 To 4
            Ws.Cells(I, J).value = Data(I).Item(J)
        Next
    Next
    
    Path(2) = "xls"
    Dim ExpPath As String
    ExpPath = GetNewName(JoinPathName(Path))
    Call Wb.SaveAs(ExpPath)
    ExpXls = ExpPath
End Function

'Excel取得
Private Function GetExcel() As Object
    Dim Xlapp As Object 'As Excel.Application
    On Error Resume Next
        Set Xlapp = VBA.GetObject(, "Excel.Application")
    On Error GoTo 0
    If IsNothing(Xlapp) Then
        MsgBox "Excelを起動してから再度実行してください"
        End
    End If
    Set GetExcel = Xlapp
End Function

'エクスポート - txt,csv
Private Function ExpTxt(ByVal Path As Variant, ByVal Data As Collection, _
                        ByVal Delim As String, ByVal Ext As String) As String
    Dim Tmp As Collection: Set Tmp = New Collection
    Dim Info As Collection
    For Each Info In Data
        Call Tmp.Add(JoinLst(Info, Delim))
    Next
    
    Path(2) = Ext
    Dim ExpPath As String
    ExpPath = GetNewName(JoinPathName(Path))
    Call WriteFile(ExpPath, JoinLst(Tmp, vbNewLine))
    
    ExpTxt = ExpPath
End Function

'リスト展開
Private Function JoinLst(ByVal Lst As Collection, ByVal Delim As String)
    Dim t As Variant
    Dim res As String
    For Each t In Lst
        res = res & t & Delim
    Next
    JoinLst = Left(res, Len(res) - Len(Delim))
End Function

'座標値取得
Private Function GetPointInfo(ByVal Msg As String, _
                              ByVal Filter As Variant) As Collection
    Dim Sel As Variant: Set Sel = CATIA.ActiveDocument.Selection
    Dim Data As Collection: Set Data = New Collection
    Dim Info As Collection
    Dim Pnt As Variant 'As Point
    Dim Pos(2) As Variant 'As Double
    
    Do
        Sel.Clear
        Select Case Sel.SelectElement2(Filter, Msg, False)
            Case "Cancel", "Undo", "Redo"
                Exit Do
        End Select
        Set Pnt = Sel.Item(1).value
        Call Pnt.GetCoordinates(Pos)

        Set Info = New Collection
        With Info
            Call .Add(Pnt.Name)
            Call .Add(CStr(Pos(0)))
            Call .Add(CStr(Pos(1)))
            Call .Add(CStr(Pos(2)))
        End With
        Call Data.Add(Info)
    Loop
    Set GetPointInfo = Data
End Function

'ドキュメントのパス取得
Private Function GetDocDir(ByVal Doc As PartDocument) As Variant
    Dim Path As Variant
    Path = SplitPathName(Doc.FullName)
    If Len(Path(0)) < 1 Then
        MsgBox "CATPartファイルを一度保存してください!!)"
        End
    End If
    GetDocDir = Path
End Function

'*** kclより流用 ***
'こちらを同じプロジェクト内にKCL.bas(標準モジュール)として入れてある場合は
'以下のコードは不要です。
'http://kantoku.hatenablog.com/entry/2016/06/21/111410
'http://kantoku.hatenablog.com/entry/2016/12/27/194117


'マクロスタートチェック
''' @param:DocTypes-array(string),string マクロ実行を許可するドキュメントのタイプ
''' @return:Boolean
Private Function CanExecute(ByVal DocTypes As Variant) As Boolean
    CanExecute = False
    
    If CATIA.Windows.Count < 1 Then
        MsgBox "ファイルが開かれていません"
        Exit Function
    End If
    
    If VarType(DocTypes) = vbString Then DocTypes = Split(DocTypes, ",")
    If Not IsFilterType(DocTypes) Then Exit Function
    
    Dim ErrMsg As String
    ErrMsg = "ファイルのタイプが異なります。" + vbNewLine + "(" + Join(DocTypes, ",") + " のみです)"
    
    Dim ActDoc As Document
    On Error Resume Next
        Set ActDoc = CATIA.ActiveDocument
    On Error GoTo 0
    If ActDoc Is Nothing Then
        MsgBox ErrMsg, vbExclamation + vbOKOnly
        Exit Function
    End If
    
    If UBound(Filter(DocTypes, TypeName(ActDoc))) < 0 Then
        MsgBox ErrMsg, vbExclamation + vbOKOnly
        Exit Function
    End If
    
    CanExecute = True
End Function

'フィルタータイプとしてOK?
Private Function IsFilterType(ByVal Ary As Variant) As Boolean
    IsFilterType = False
    Dim ErrMsg$: ErrMsg = "フィルター又はドキュメントタイプの指定は" + vbNewLine + _
                          "Variant(String)型配列で行ってください" + vbNewLine + _
                          "(マクロコードのエラーです)"
    
    If Not IsStringAry(Ary) Then
        MsgBox ErrMsg
        Exit Function
    End If
    
    IsFilterType = True
End Function

'文字型配列?
Private Function IsStringAry(ByVal Ary As Variant) As Boolean
    IsStringAry = False
    
    If Not IsArray(Ary) Then Exit Function
    Dim I&
    For I = 0 To UBound(Ary)
        If Not VarType(Ary(I)) = vbString Then Exit Function
    Next
    
    IsStringAry = True
End Function

'FileSystemObject
''' @return:Object(Of FileSystemObject)
Private Function GetFSO() As Object
    Set GetFSO = CreateObject("Scripting.FileSystemObject")
End Function

'パス/ファイル名/拡張子 分割
''' @param:FullPath-ファイルパス
''' @return:Variant(Of Array(Of String)) (0-Path 1-BaseName 2-Extension)
Private Function SplitPathName(ByVal FullPath$) As Variant
    Dim Path(2) As String
    With GetFSO
        Path(0) = .getParentFolderName(FullPath)
        Path(1) = .GetBaseName(FullPath)
        Path(2) = .GetExtensionName(FullPath)
    End With
    SplitPathName = Path
End Function

'パス/ファイル名/拡張子 連結
''' @param:Path-Variant(Of Array(Of String)) (0-Path 1-BaseName 2-Extension)
''' @return:ファイルパス
Private Function JoinPathName$(ByVal Path As Variant)
    If Not IsArray(Path) Then Stop '未対応
    If Not UBound(Path) = 2 Then Stop '未対応
    JoinPathName = Path(0) + "\" + Path(1) + "." + Path(2)
End Function

'ファイル,フォルダの有無
''' @param:Path-パス
''' @return:Boolean
Private Function IsExists(ByVal Path$) As Boolean
    IsExists = False
    Dim FSO As Object: Set FSO = GetFSO
    If FSO.FileExists(Path) Then
        IsExists = True: Exit Function 'ファイル
    ElseIf FSO.FolderExists(Path) Then
        IsExists = True: Exit Function 'フォルダ
    End If
    Set FSO = Nothing
End Function

'重複しない名前取得
''' @param:Path-ファイルパス
''' @return:新たなファイルパス
Private Function GetNewName$(ByVal OldPath$)
    Dim Path As Variant
    Path = SplitPathName(OldPath)
    Path(2) = "." & Path(2)
    Dim NewPath$: NewPath = Path(0) + "\" + Path(1)
    If Not IsExists(NewPath + Path(2)) Then
        GetNewName = NewPath + Path(2)
        Exit Function
    End If
    Dim TempName$, I&: I = 0
    Do
        I = I + 1
        TempName = NewPath + "_" + CStr(I) + Path(2)
        If Not IsExists(TempName) Then
            GetNewName = TempName
            Exit Function
        End If
    Loop
End Function

'ファイルの書き込み
''' @param:Path-ファイルパス
''' @param:Txt-String
Private Sub WriteFile(ByVal Path$, ByVal txt) '$)
    Call GetFSO.OpenTextFile(Path, 2, True).Write(txt)
End Sub

マクロ起動後、大したメッセージもありませんが点を次々とクリックして頂き
ESCキーを押す事でCATPartファイルと同じフォルダ内に
"[CATPartファイル名]_SelPoint.xxx "
と言う名称のファイルが出来上がります。
(上書き保存を避けるため、同一名のファイルがある場合 "_[数字]"が追加されます)

・CATPartファイルがアクティブになっている必要が有り、一度保存しておく必要が有ります。
 (保存先パスを取得する為)
・事前にコードを設定する必要がありますが(最初の方の部分です)、対応フォーマットは
 txt,csv,xlsです。
・xlsの場合、事前にExcelを起動しておく必要が有ります。
・エクスポートされたファイルは以下の状態です。
 [名称 , X値 , Y値 , Z値]
Excel操作部分のコードは、世間の皆様の方がきっと素晴らしいと思います。
・コード内にも記載しましたが、KCLを利用する場合は後半のコードは不要です。
非常に個人的なCATVBA用ライブラリ - C#ATIA
不覚にも、KCLのご利用をお考えの方へ - C#ATIA

マクロ中毒

先日、こちらを見つけました。
Solved: Macro addict - Autodesk Community
僕が試したところ0個でした。 (たった1行の)コードを把握してないので
何とも言えませんが、恐らくマクロのパスの設定が原因だろうと思います。

それにしても、常連さん達は200~300個ぐらいザラなんですね・・・。
確かにPowerMillのマクロは手動で出来る事は、ほぼ全てマクロで可能です。
( ' ほぼ ' は、今まで出来なかったものに遭遇した事が無いと言う意味です)

CATIA_V5,Fusion360,PowerMill,AdvanceCAD・・・全部合わせても300も
無いような気がしてます。

まだまだ初心者ですね。

加工モレを発生させない領域を作り出す

長年悩まされていた事がちょっと解決しそうだな と言うお話です。

こんな形状を加工しようと思った場合なのですが、
f:id:kandennti:20180306165000p:plain
紫色は勾配の付いた面で、ピンク色が水平な面です。

傾斜している部分があるので、ボールエンドミルで加工するのですが
大きな水平面がある為、水平面は出来るだけスクエアエンドミルで加工したい。
こんな場合、世間の皆様はどの様な加工領域を作っているのでしょうか?
(知りたい・・・)

生憎、企業秘密的な理由?でWeb上では見つけ出すことが出来ないのが
現状です。まぁ、この程度の形状であれば細かい事を気にしないで
大まかな加工領域をスケッチ等で作ってしまえば良いのですが・・・。


単純な方法でΦ10のエンドミルで水平面を、R2のボールエンドミルで水平面以外を
加工するとして考えてみます。

大きな水平面2つの境界線を作ります。
f:id:kandennti:20180306165008p:plain

3個の境界線が出来上がるのですが、2つのエンドミルで多少ラップした
状態(1mm)で仕上げるとして考え、
赤:不要なので削除
黄:内側に1mmオフセット
緑:外側に3mm(R2+1mm)オフセット
してみます。
f:id:kandennti:20180306165023p:plain

こんな感じの黄色で囲まれた部分をボールエンドミルで仕上げて、残りを
スクエアエンドミルで仕上げるツールパスを作るわけです。(座標系が邪魔・・・)
f:id:kandennti:20180306165033p:plain

細かい事を考えずにこんな感じで作りました。まだまだゴールじゃないんです。
f:id:kandennti:20180306165040p:plain

確認の為、ストックモデルを利用して加工モレが無いか? 確認してみます。
(PowerMillの場合、加工モレのチェックはViewMill(シミュレーション)の機能で出来ない気がします)
見落としてしまいそうな程小さいのですが、赤印部分に加工モレが・・・
f:id:kandennti:20180306165052p:plain

ズームし上から見てみると、こんな感じです。
f:id:kandennti:20180306165059p:plain
黄色はΦ10エンドミル工具で、白い線はR2ボールエンドミルのツールパスです。
面の境界から単純なオフセットで加工する領域を作成すると鋭角な凹形状部に
加工モレが出来てしまうんです。(意図的にそんな形状にしたんです)



以前は、これを防ぐ為にCATIA上でチマチマGSDの機能で加工領域となる線を
作っていたのですが、やはり時間がかかりすぎなんです。
(ここが最初に記載した悩み部分)

サポートに相談したところ回答を頂いたものの、少し手順が複雑で間違えそうな
気配たっぷりで断念したのですが、PowerMillの機能的な面でヒントは頂きました。


まず、Φ10エンドミルでのツールパスを作成します。
f:id:kandennti:20180306165112p:plain
赤印部分の小さな凹部分ですが、わかる方にはわかるのですが、
仕上がらない為に削除します。(意図的にそんな形状にしたんです)

続いてこのツールパスに対して、以下のマクロ実行します。

//pm2018 macro
//Path2Rest_Boundary.mac Ver0.0.1
//ツールパスから削り残しバウンダリを作成
//---------------------------------------------------------------------------------------------------
//<?xml version="1.0" ?>
//<menupage>
//   <button label="パスからバウンダリ作成" command='MACRO toolpath\Path2Rest_Boundary.mac "%s"' />
//</menupage>
//---------------------------------------------------------------------------------------------------
//Path2Rest_Boundary
Function Main(string tp) {
	//ユーザー選択
	string tool = ''
	call SelectTool($tp , $tool) 
	
	//パスアクティブ - blockの為
	call Msgoff()
	activate toolpath $tp
	
	//ストックモデル
	string stk = ''
	call InitStockModel($tp , $stk)

	//バウンダリ
	call InitBoundary($stk , $tool) 
	
	//終わり
	deactivate toolpath
	call Msgon()
	message info 'Done'
}

//工具選択
Function SelectTool(string tp , output string out) {
	string msg = "工具を選んでください" 
	string tool = tool.name
	$tool = input entity tool $msg
	
	bool yn = 0
	$msg = 'ツールパス [ ' + $tp + ' ] に対して 工具 [ ' + $tool + ' ] の' + crlf
	$msg = $msg + '削り残しバウンダリを作成しますか?'
	$yn = QUERY $msg
	if $yn != 1 {
		macro abort
	}
	$out = $tool 
}

//ストックモデル
Function InitStockModel(string tp , output string out) {
	string tmp = new_entity_name('stockmodel')
	string stk = ''
	call GetNewName('stockmodel'  , 'from_' + $tp , $stk)
	CREATE STOCKMODEL ; FORM STOCKMODEL
	RENAME StockModel $tmp $stk
	entity stkmdl = entity('stockmodel' , $stk)
	$stkmdl.TOLERANCE = 0.01
	$stkmdl.STEPOVER = 0.5
	$stkmdl.ThresholdThickness = 0.2
	FORM ACCEPT STOCKMODEL
	EDIT STOCKMODEL $stk DRAW REST
	UNDRAW StockModel $stk
	EDIT STOCKMODEL ; INSERT_INPUT TOOLPATH $tp LAST
	
	$out = $stk
}

//バウンダリ
Function InitBoundary(string stk  ,string tool) {
	string tmp = new_entity_name('boundary')
	//StockRest
	string stkrest = ''
	call GetNewName('boundary' , $stk + '_Rest', $stkrest)
	CREATE BOUNDARY ; STOCKMODEL_REST FORM BOUNDARY
	RENAME Boundary $tmp $stkrest
	EDIT BOUNDARY $stkrest STOCKMODEL $stk
	EDIT BOUNDARY $stkrest STOCKMODEL_THICKER "0.2"
	EDIT BOUNDARY $stkrest EXTEND "0.5"
	EDIT BOUNDARY $stkrest TOLERANCE ".02"
	EDIT BOUNDARY $stkrest LIMIT OFF
	call SetBoundary($stkrest  ,$tool) 
	
	//Silhouette
	string slete = ''
	call GetNewName('boundary' , $stk + '_Fin' , $slete)
	CREATE BOUNDARY ; SILHOUETTE FORM BOUNDARY
	RENAME Boundary $tmp $slete 
	EDIT BOUNDARY $slete SILVERTICAL UP
	EDIT BOUNDARY $slete TOLERANCE "0.01"
	EDIT BOUNDARY $slete VERTTOLERANCE "0.01"
	EDIT BOUNDARY $slete LIMIT ON
	EDIT BOUNDARY $slete LIMIT INSIDE
	EDIT BOUNDARY $slete LIMIT_BOUNDARY $stkrest
	call SetBoundary($slete  ,$tool) 
	EDIT BOUNDARY $slete CALCULATE
}

//バウンダリ共通パラメータ設定
Function SetBoundary(string bou  ,string tool) {
	EDIT BOUNDARY $bou THICKNESS AXIAL_RADIAL OFF
	EDIT BOUNDARY $bou THICKNESS "0.0"
	EDIT BOUNDARY $bou TOOL NAME $tool
	EDIT BOUNDARY $bou PRIVATE NO
	EDIT BOUNDARY $bou AUTOREPLAY NO
	EDIT BOUNDARY $bou IGNORE_HOLDER
	EDIT BOUNDARY $bou BLOCK_LIMIT PERIPHERY
	EDIT BOUNDARY $bou ACCEPT BOUNDARY ACCEPT
	return
}

//新たな名前の取得
Function GetNewName(string folder , string name , output string out) {
	if entity_exists(entity($folder ,$name)) < 1 {
		$out = $name
	} else {
		$out = new_entity_name($folder ,$name)
	}
	return
}

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

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

実行時はこんな感じです。

実際の業務では、ゴチャゴチャした形状なのでこんなに短時間では処理が
終わらないのですが、それでも放置しておけば処理が終わるので
今までのチマチマ手法より遥かに楽で、今のところ加工モレも出ていません。

Space-eだと、チマチマ手法しか無いんですよね。

表示幅を変更しました

VBAPythonは何とでもなるのですが、PowerMillのマクロコードが
どうしても横長になり過ぎ、見にくい為変更してみました。

はてなブログの記事の横幅を広げる方法 (テーマ:solidの場合) - Engineer's Way

「そもそもお前のコードがナンセンスだからだ」と言われると
返す言葉も無いのですが、複数行を1行とする記法がPowerMillマクロ
には存在しないようだからです。

ついでに、この独自の言語の特徴を僕なりの印象で書くと
・スコープの大きい変数が作れない(構わない)
・重複する関数名でもエラーにならず、先頭のものが優先される(怖い)
・自作関数の戻り値は通常の方法では受け取れず、引数部で受け取る(不便)
・リストの中にリストが作れない(不便)
・リストを操作する標準関数が充実している(VBAとは比較にならない程すごい)

コード部分の表示自体も修正したのですが、何処を参考にしたのか
忘れました。 ごめんなさい。

追記です。
複数行を1行とする記法がありました。
単につじつまが合えば改行して記載してもエラーにはならないようです。

Function Main( ){
	call hoge(1,2)
}

function hoge(int a, 
	int b)
{
	int c =
	a + b
	return
}

こんな表記もOKでした。 読みやすいのかどうかは別問題・・・。

Tコード順の工具リストを作成する

まだまだ、PowerMillが使いこなせず悩んでます。
その1つが段取りする為の工具のリスト。

ISOコード(Gコード)出力する際、PowerMillではこんな感じになり
それぞれをポスト処理します。
f:id:kandennti:20180302190324p:plain
その際セットアップシート(段取指示書、作業指示書・・とか)を作る事が
どのCAMソフトでも出来る物ですが、こんな感じの物を作って使用しています。
f:id:kandennti:20180302190334p:plain
フォーマット自体は自由に変更できるのですが、どのCAMソフトでも不満なのは
工程順に出力される部分です。(当然、それも欲しいのですが)

実際に現場で段取りを行う際は、工程順ではなくTコード順に工具の用意や
確認をしたいんです、僕は。

過去にSpace-eでもサポートさんにこの件を何度か伝えたのですが、
未だ実現されてません。(プラグインの作り方も教えてもらえない・・・)


先日、PowerMillのフォーラムでこちらを見つけました。
Tool Tree Set-Up Sheet - Autodesk Community
よくこんなものを作れるなぁ と言うのが本音です。

幾つかのタイプがあるのですが、個人的に使いやすいように(劇的に)直しました。
・フランス語 → 日本語
・Tコード順にソート ← これが一番の目的
・マルチセレクト時、個別ではなく集計しエクスポート
・項目・表示の見直し
・コードがイロイロと汚い・・・
 (ファイル開きっぱなしで、ループし処理しつつ書き出しは許せない)

//pm2018 macro
//UseToolList.mac Ver0.0.1
//選択済みNCプログラムから工具リストを作成
//---------------------------------------------------------------------------------------------------
//本マクロはコンテキストメニューからの起動の為、ncprogram.XMLに追記してください
//<?xml version="1.0" ?>
//<menupage>
//   <button label="使用工具リスト" command='MACRO ncprogram\UseToolList.mac ' 
 multiple_selection="allowed"/>
//</menupage>
//---------------------------------------------------------------------------------------------------

function Main() {
	//シングル-処理 マルチ-最初のみ処理
	IF $PowerMILL.Status.MultipleSelection.Total  {
		IF $PowerMILL.Status.MultipleSelection.First == 0 {
			return
		}
	}
	
	//実行前チェック
	call HasProjectName()
	
	//選択要素(NCプログラム)内でツールパスを持つもののみのリスト
	entity list ncs =  {}
	call GetHasToolpathNcpro(explorer_selected_entities() ,$ncs) 
	
	//エクスポートパス取得・フォルダ作成
	string expdir = project_pathname(0) + '/NCProgramUseTools'
	MKDIR $expdir
	string exppath = $expdir+ "/UseTools.html"
	
	//Tコードによるソート済み工具リスト
	entity list tools =  {}
	call GetSortedToolLst($ncs ,$tools) 
	
	//工具イメージ
	string list imgs = {}
	call InitToolImg($tools, $expdir ,$imgs) 	
	
	//工具データ
	string list tables = {}
	call GetToolInfoTable($tools ,$imgs ,$tables)
	
	//書き出し
	string list expheader = {'<html>','<head>','<title>使用工具</title>','</head>','<body lang=FR>','<H1> 使用工具 </H1>'}
	string list expfooter ={'</body>','</html>'}
	string list exptxt = $expheader + $tables + $expfooter 
	call WriteFile($exppath , $exptxt)
	
	//ブラウザに表示
	message info  'Done'
	OLE fileaction 'open' $exppath
}

//工具画像
function InitToolImg(entity list lst, string exppath ,output string list outlst) {
	string list imgs = {}
	int dmy = 0
	string cmd = ''
	string imgname = ''
	foreach tl in lst {
        $imgname = replace($tl.name ,' ' ,'_') + '.png'
		$cmd='FORM RAISE TOOLASSPREVIEWFORM "' + $tl.name  + '"'
		docommand $cmd
		wait form //必要
		
	    $cmd='EXPORT TOOLASSEMBLYPREVIEW FILE "' + $exppath + '/' + $imgname +'"'
        docommand $cmd
		yes
		FORM CANCEL TOOLASSPREVIEWFORM
		
		$dmy = add_last($imgs , $imgname)
	}
	$outlst = $imgs
}

//工具情報
function GetToolInfoTable(entity list tools ,string list imgs ,output string list outlst) {
	string list tb_head = {'<table border=1 cellspacing=1 cellpadding=1>'}
	string list tb_foot = {'</table>'}
	
	//テーブルタイトル
	string list tb_title = {'イメージ','Tコード','径/ノーズR','タイプ','シャンク径/首下','ホルダ径/突出','ホルダ名'}
	string tmp = ''
	call Join2SrtLst($tb_title ,'<TD align="center" ><H3>', '</H3></TD>' ,$tmp)
	$tmp = '<TR>' + $tmp + '</TR>'
	$tb_title = {$tmp}
	
	//イメージタグ用
	string browser = '15%' //Chrome
	//string browser = '80p' //IE 上手く行かない

	//テーブル中身 タイトルと合わせてね
	string list tb_infos = {}
	string list vals = {}
	int dmy = 0
	int cnt = -1
	foreach tl in tools {
		$vals = {}
		$cnt = $cnt + 1
		
		$dmy = add_last($vals , '<img src="./' + $imgs[$cnt] + '" alt="' + $tl.name + '"  height="' + $browser +'"/>')
		$dmy = add_last($vals , string($tl.Number.Value))
		$dmy = add_last($vals , 'D' + string(round($tl.Diameter,3)) + '/R' + string(round($tl.TipRadius,3)))
		$dmy = add_last($vals , string($tl.Type))
		$dmy = add_last($vals , 'D' + string(round($tl.ShankSetValues[0].UpperDiameter,3))+ '/' + string(round($tl.Length,3)))
		$dmy = add_last($vals , 'D' + string(round($tl.HolderSetValues[0].LowerDiameter,3))+ '/' + string(round($tl.Overhang,3)))
		$dmy = add_last($vals , $tl.HolderName)
		
		call Join2SrtLst($vals ,'<TD align="center" >', '</TD>' ,$tmp)
		$tmp = '<TR>' + $tmp +'</TR>'
		$dmy = add_last($tb_infos  ,$tmp)
	}
	
	$outlst = $tb_head + $tb_title + $tb_infos  + $tb_foot
}

//Tコードによるソート済み工具リスト
function GetSortedToolLst(entity list ncs ,output entity list outlst) {
	string list tools = {}
	foreach nc in ncs {
		$tools = $tools + list_nctools($nc)
	}
	int dmy = 0
	$dmy = remove_duplicates($tools)
	
	entity list nctools = {}
	foreach toolname in tools {
		$dmy = add_last($nctools , entity('Tool',$toolname))
	}	
	$nctools = sort($nctools ,'tool.number')
	$outlst = $nctools
}

//StrLstの連結
function Join2SrtLst(string list lst ,string SepFront ,string SepRear ,output string out) {
	string s = ''
	foreach t in lst {
		$s = $s + $SepFront + $t + $SepRear
	}
	$out = $s
}

//ファイル書き出し
function WriteFile(string path ,string list lst) {
	string s = ''
	call Join2SrtLst(lst ,'' ,crlf ,$s)
	FILE OPEN $path FOR WRITE AS file
	FILE WRITE $s TO file
	FILE CLOSE file
}

//ツールパスを持っているNcデータリスト
function GetHasToolpathNcpro(entity list ncs ,output entity list outlst) {
	foreach nc in $ncs {
		IF number_nctoolpaths($nc) > 0 {
			int dmy = add_last($outlst , $nc)
		}
	}
	IF is_empty($outlst) {
		string msg = '選択されたNCプログラムにはツールパスがありません!'
		MESSAGE ERROR $msg
		MACRO ABORT 
	}	
}

//保存されているプロジェクト?
function HasProjectName() {
	string $proname = project_pathname(1)
	if length($proname) > 0 {
		return
	}
	
	string msg = '一度プロジェクトを保存してください!'
	MESSAGE ERROR $msg
	MACRO ABORT 
}

NCプログラムのコンテキストメニューから実行すると、こんな感じで
ブラウザ(PowerMillでは無い通常の)で表示されます。
f:id:kandennti:20180302190353p:plain
工具のイメージがエクスポート出来る機能があるなんて知りませんでした・・・。

使う人がいるとは思えないのですが、オリジナルと項目を変更しているので
f:id:kandennti:20180302190405p:plain
「シャンク径/首下」のシャンク径は、上の画像の赤矢印部分です。
 シャンクの1段目の上の径を出力してます。

「ホルダ径/突出」のホルダ径は、画像の青矢印部分です。
 ホルダの1段目の下の径を出力しています。


・・・CATIAはネタが無いなぁ。

加工前チェック用ツールパスの作成

マシニングセンターで加工する前に材料の位置やサイズ、ワーク座標系等
どうやって確認するのが一般的なんでしょうか?(・・・知りたい)

これらのミスでオシャカを作った場合(だけではないと思いますが)対策書を
書かされる企業も多くあるかと思いますが、大半の対策は「よく確認する」に
なってしまうのも本音なところw

僕のところでは暗黙的なルールとして、材料の天面をクルッと走らせるだけの
簡単なツールパスを走らせて確認しています。こんな感じの緑の線です。
f:id:kandennti:20180221192411p:plain
機械が一生懸命仕事をしているのを拝んでる暇が無いので、この確認だけで
あとは放置です。基本的に。

実はこんな簡単なツールパスなのですが、PowerMillでは空中に浮いている
無意味なものを作るのが結構難しい?面倒?なのです。

そこでマクロを利用し手っ取り早く作れるようにしました。

//pm2018 macro
//チェックパス作成

function Main(string toolname) {
	bool yn = 0
	string msg = '' 
	string pro_ptf_path = 'check_path.ptf' 

	//Planesモデルチェック
	if entity_exists(entity('Model','Planes')) > 0 {
		$msg = 'Placesモデルを削除しマクロを実行しますか?'
		$yn = QUERY $msg
		if $yn < 1 {
			return
		} else {
			Call Del_Planes()
		}
	}

	//**ユーザー選択**
	//モデル
	$msg = '参照モデルを選択してください'
	string list models = input entity multiple model $msg
	if is_empty(models) {
		return
	}
	
	//平面高さ
	$msg = '平面高さを入力して下さい'
	real Top = -1
	call InputReal($Msg, Block.Limits.ZMax, $Top )
	if $Top  < 0 {
		return
	}	
	
	//確認
	$msg = '工具 [ ' + $toolname +' ]  高さ [ ' + $Top+' ] で作成しますか?' 
	$yn = QUERY $msg
	if $yn  < 1 {
		return
	}	
	
	//**処理**
	call DialogOff()
	
	//ダミー面作成選択
	call Deactivete_All()
	call Select_Models(models)
	call Setting_Block($Top)
	call Init_Plane($Top)
	EDIT MODEL "Planes" SELECT ALL
	
	//工具
	ACTIVATE TOOL $toolname
	real offset_lng = tool.Diameter / 2 * -1
	
	//チェックパス作成
	call Inport_strategy($pro_ptf_path, $offset_lng) 

	//ダミー面削除
	Call Del_Planes()
	
	call DialogOn()
	
	message info 'Done'
}

//ストラテジー呼び出し・計算
function Inport_strategy(string path, real offsetlng) {
	string newToolpath = new_entity_name('Toolpath')
	
	IMPORT TEMPLATE ENTITY TOOLPATH TMPLTSELECTORGUI $path
	EDIT PAR 'RadialOffset' $offsetlng
	EDIT TOOLPATH SAFEAREA CALCULATE_DIMENSIONS
	EDIT TOOLPATH $newToolpath CALCULATE
	FORM ACCEPT SFPatternProf
	
	string rename = new_entity_name('Toolpath','check')
	RENAME Toolpath $newToolpath $rename
	
	// DRAW Toolpath $rename//表示はお好みで
}

//Planes モデルとレベルの削除
function Del_Planes() {
	DELETE MODEL "Planes"
	DELETE LEVEL "Planes"
}

//ダミー面作成
function Init_Plane(real top) {
	CREATE PLANE ; $top
}

//ブロック修正
function Setting_Block(real top) {
	FORM BLOCK
	EDIT BLOCK ALL UNLOCK
	EDIT BLOCKTYPE BOX
	EDIT BLOCK COORDINATE WORKPLANE
	EDIT BLOCK RESETLIMIT "0"
	EDIT BLOCK TOLERANCE "0.1"
	EDIT BLOCK LIMITTYPE MODEL
	EDIT BLOCK RESET
	EDIT BLOCK ZMAX $top
	BLOCK ACCEPT
	
	EDIT MODEL ALL DESELECT ALL
}

//指定モデル面の選択
function Select_Models(string list models) {
	EDIT MODEL ALL DESELECT ALL
	foreach mdl in $models {
		EDIT MODEL $mdl SELECT ALL
	}
}

//非アクティブ_非表示 - 作業平面は行わない,レベルの非表示は行わない
function Deactivete_All() {
	DEACTIVATE NCPROGRAM
	DEACTIVATE TOOLPATH
	DEACTIVATE TOOL
	DEACTIVATE BOUNDARY
	DEACTIVATE PATTERN
	DEACTIVATE FEATURESET
	DEACTIVATE FEATUREGROUP
	DEACTIVATE LEVEL
	DEACTIVATE STOCKMODEL
	DEACTIVATE GROUP
	
	UNDRAW NCPROGRAM ALL
	UNDRAW TOOLPATH ALL
	UNDRAW TOOL ALL
	UNDRAW BOUNDARY ALL
	UNDRAW PATTERN ALL
	UNDRAW FEATURESET ALL
	UNDRAW FEATUREGROUP ALL
	UNDRAW STOCKMODEL ALL
	UNDRAW GROUP ALL
}

//数値入力 不正時は-1を返す
function InputReal(string Msg, real Defreal, output real  Outreal) {
	$Outreal = -1
	real res = $Defreal
	$res = input $Msg
	bool err = 0
	$err = error $res
	if $err {
		message error '数値を入力して下さい!'
		return
	} 
	if $res <=0 {
		message error '0以上の数値を入力して下さい!'
		return
	} 	
	$Outreal = $res
}

//ダイアログ類オン
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
}

ツールパスを作成する工具のコンテキストメニューからの呼び出し用のマクロです。
又、本マクロ以外に「輪郭加工仕上げ」機能を有る程度設定している
ストラテジーファイル(PTFファイル)が同一フォルダ内に必要です。
(ので、他人には全く無意味なマクロになっています)

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

制限です。
・一時的にPowerMill内で平面を作成し、ツールパスを作成しています。
 最後に全ての一時的な面を削除している為、同機能を使用し作成された面は
 全て削除されてしまいます。

・本ツールパスは「輪郭加工仕上げ」機能を使用し作成されます。
 この機能は参照する面を選択して使用する機能ですが、一時的に作成した面を
 削除して終了する為、ツールパス自体の再計算が出来ません。
 (「送り/速度」「ツールパスコネクター」での再設定は可能です)
 その為、修正が必要な場合はマクロを再実行する必要が有ります。

Igesデータのインポート率改善

ネタ無い以上に、私事が忙しいです。

CATIAからエクスポートしたIgesデータをPowerMillに取り込んで作業するのですが、
導入時からインポート率が悪く、結構悩まされていたのですが、
先日こちらの記述を発見しました。
IGES 内のサーフェスがない PowerMill のインポート時にファイル | PowerMill | Autodesk Knowledge Network
ロボット翻訳の為、怪しげな日本語になっていますが意図は伝わりました。
(ファイルパスまで翻訳されている為、英語の方がわかりやすいかも)

実際に設定してみると、劇的に改善。 面抜けもほぼ無くなり、面の向きも
こちらのマクロでかなりの確立で整うようになりました。
バッチ処理前にマクロでモデルをチェックする - C#ATIA

以前、サポートに聞いても、この設定は教わりませんでした。
(CATIA側はBスプラインで設定した方が良いです。 ・・・他のCADCAMでも。)


又、頑張って英語で質問中。(グーグル先生のお陰です)
[MACRO] Judge that the cancel button is pushed - Autodesk Community
意味伝わるかな? 恐らく答えは出ないような気がしてます。