C#ATIA

↑タイトル詐欺 主にCATIA V5 の VBA(最近はPMillマクロとFusion360APIが多い)

続・水 問題

相変わらず勘弁して欲しい程忙しい。

9L(3^2)と16L(4^2)の容器で、13L(4^2以下の最大素数)を作る
の答えを書いていなかったので、こちらの続きです。
水 問題 - C#ATIA
(週末アクセス数が閑古鳥なのですが、先週は意外な程アクセスが・・・。)

・9L(9)→ 16L(0)
・9L(0) 16L(9)
・9L(9)→ 16L(9)
・9L(2) 16L(16)
・9L(2)→ 16L(0)
・9L(0) 16L(2)
・9L(9)→ 16L(2)
・9L(0) 16L(11)
・9L(9)→ 16L(11)
・9L(4) 16L(16)
・9L(4)→ 16L(0)
・9L(0) 16L(4)
・9L(9)→ 16L(4)
・9L(0) 16L(13)

長い・・・手数は最短だと思ってます(根拠なし)。
13Lを作り出す為のリーチ(麻雀)は

9L(9)→ 16L(4)

9L(6)← 16L(16)

だろうと思い、頭の中で必死に 4L か 6L を作り出す手順を
探した末です。4Lが出来た瞬間、声を出して喜んだのは内緒です。

水 問題

業務が忙しくなり、スプリクトの続きがしばらく書けそうにないです。

子供の宿題で「先生にクイズを出す」と言うものが終わっていない との事。
風呂で一緒に考えていました。以前出した
「4Lの容器と9Lの容器の2つを使って、7Lの水を作り出す」
と言う話になったのですが、結構有名な問題だろうと思います。
検索すれば、この辺にも(リンク先は文字化けしてません)
 ‹‚‚݃NƒCƒY - “k‘
正直、先生に出すには簡単すぎるとは思うので、少し数字を変えては
どうか? と提案しました。 では幾つにするか?

そもそも4・9・7の数字が選ばれた経緯はわからないのですが、個人的に

4(2^2) 9(3^2) 7(3^2以下の最大素数)

と直感的に感じたので、1つずらして

9L(3^2)と16L(4^2)の容器で、13L(4^2以下の最大素数)を作る

と言うのはどうだろうか? と提案。

提案したものの、風呂の中では答えを見つけ出す事が出来ませんでした…。
(結果的に、答えが見つからなかったので宿題としては没)
寝かせる直前には見つかりましたが。


もう一個ずらして

16L(4^2)と25L(5^2)の容器で23L(5^2以下の最大素数)

を出した所、子供があっさり答えを見つけました。
※カッコ内は容器内の水の量、矢印は次の水の動き
・16L(16)→ 25L(0)
・16L(0) 25L(16)
・16L(16)→ 25L(16)
・16L(7) 25L(25)
・16L(7)→ 25L(0)
・16L(0) 25L(7)
・16L(16)→ 25L(7)
・16L(0) 25L(23)

数字が大きいと難しいと思ったのですが、そうでもないみたいです。

バウンダリのまとめて変更する

以前、工具のコンテキストメニューから交換可能なツールパスを
リストアップし、複数の任意のツールパスの工具を変更出来るように
するマクロを作りました。
工具コンテキストメニューから工具変更2 - C#ATIA
想像以上に効率が良く、頻繁に使用しています。

最近になり、バウンダリの作り方のコツがわかってきた(日々勉強)
のですが、ツールパスにバウンダリを割り当てるのが面倒に
なってきました。 そこで工具変更に類似したバウンダリ変更マクロ
を作成しました。

//pm2020 macro
//ReplaceBoundary.mac ver0.0.1
//バウンダリ変更
//---------------------------------------------------------------------------------------------------
//<?xml version="1.0" ?>
//<menupage>
//   <button label="バウンダリ変更" command='MACRO Boundary\ReplaceBoundary.mac "%s"'/>
//</menupage>
//---------------------------------------------------------------------------------------------------
//ver0.0.1-完成
//---------------------------------------------------------------------------------------------------

function main(string boundaryname) {

	//交換可能リスト	計算済み・同一バウンダリ除外
	string filter = 'Computed == 0 and Batch == 1'
	$filter = $filter + 'and boundary.name != "' + boundaryname +'"'
	string list paths =  extract(filter(folder('toolpath'), filter), 'name') 
	
	if is_empty($paths) {
		message error  '変更可能なツールパスがありません!!'
		return
	}
	
	//ユーザー確認
	string msg = '[' + $boundaryname + ']' + 'にバウンダリを変更するツールパスを選択してください'
	call Exec_DownMenu($paths, $msg, 1, $paths)
	
	//工具交換
	call Replace_Boundary($boundaryname, $paths)
	
	//終了
	message info  'Done'
}

//バウンダリ変更
function Replace_Boundary(string bou, string list Lst) {
	foreach path in $Lst {
		ACTIVATE TOOLPATH $path
		ACTIVATE BOUNDARY $bou
		EDIT TOOLPATH $path REAPPLYFROMGUI
	}
}

include downmenu.inc

やっぱり、PowerMillはバウンダリの作り方・使い方で腕の差が出る!!

Fusion360スプリクト作成の取っ掛かり3

こちらの続きです。
Fusion360スプリクト作成の取っ掛かり2 - C#ATIA

前回までは、何かの処理を行うためのオブジェクトの探し方を行いました。
(多々不足していますが・・・)

実際にスプリクトを作成する際、毎回事前選択するのは現実的ではありません。
今回は、比較的お手軽なユーザーによる要素の選択方法を行ってみましょう。

Fusion360のスプリクトに挑戦し始めた頃、この機能を探し回ったのですが
サンプルが見つからず、ナカナカ見つけ出すことが出来ませんでした。
結論を書くと、UserInterface オブジェクトの selectEntity メソッドを
利用することになります。
Help
説明書きされていますが、単体の要素の選択のみが提供されています。

こちらを見ればわかるのですが、2つのパラメータが必要です。
Help

prompt - マウスカーソルを止めているとツールチップとして表示される文字
filter - 選択要素を制限する為のフィルター

フィルターに関しては、こちらにリストがあります。
Help

実は不具合があり、一部のフィルターが機能していません。(恐らく直っていません)
Re: Select SketchConstraints using api - Autodesk Community


これらを考慮した上で、ソリッドのボディを選択するコードを作成しました。

#FusionAPI_python サンプル
#Author-kantoku
#Description-要素の選択

import adsk.core, adsk.fusion, traceback

def run(context):
    ui = adsk.core.Application.cast(None)
    try:
        #fusion360の取得
        app = adsk.core.Application.get()
        ui  = adsk.core.UserInterface.cast(app.userInterface)
        
        #選択
        msg = 'ソリッドのボディを選択してください/ESC-キャンセル'
        item = Sel(msg ,'SolidBodies')
        if item is None:
            return #中止
        
        #キャスト 必ず行う必要は無いです
        solid = adsk.fusion.BRepBody.cast(item)
        
        #情報の取得
        infos = []
        infos.append('ボディ名 : {}'.format(solid.name))
        infos.append('所属コンポーネント名 : {}'.format(solid.parentComponent.name))
        infos.append('面数 : {}'.format(solid.faces.count))
        infos.append('辺数 : {}'.format(solid.edges.count))
        infos.append('頂点数 : {}'.format(solid.vertices.count))
        
        #表示
        ui.messageBox('\n'.join(infos))
        
    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
            
#選択
def Sel(msg, selFilter):
    app = adsk.core.Application.get()
    ui  = app.userInterface
    try:
        #選択時
        return ui.selectEntity(msg, selFilter).entity
    except:
        #ESCキー時
        return None

selectEntityが機能している(選択待ち)際、ESCキーを押すと処理が中止されますが
エラーとなっています為、例外処理で対応しています。(その為Sel関数にしています)

試しにこんなデータを作ってみました。
f:id:kandennti:20190703234444p:plain
丸 - ソリッド
四角 - サーフェス
三角 - メッシュ
です。先程のスプリクトを実行し選択しようとすると
こんな状態になります。
f:id:kandennti:20190703234459p:plain
ん~画像ではわかりにくいのですが、マウスカーソルがソリッド上にある時のみ
ハイライトした状態となり、選択可能だとユーザーはわかりますし、
それ以外の場合は、選択も出来ない状態となります。
f:id:kandennti:20190703234513p:plain

では、この状態でソリッドとサーフェスの両方を選択可としたい場合
どうすれば良いのでしょうか? 実は長い間出来ないものと思っていましたが
この様にすれば可能です。

・・・
        #選択
        msg = 'BRepなボディを選択してください/ESC-キャンセル'
        item = Sel(msg ,'SolidBodies,SurfaceBodies')
        if item is None:
            return #中止
・・・

フィルターとなる部分に ",(カンマ)" 区切りの1つの文字列で指定する事で
複数のタイプのフィルターが可能です。
これ、Helpに記載されてないんですよね。
f:id:kandennti:20190703234531p:plain


これで少し作成するスプリクトの幅が広がりますよね?

Fusion360スプリクト作成の取っ掛かり2

こちらの続きです。
Fusion360スプリクト作成の取っ掛かり1 - C#ATIA

昨夜は押し出しで説明するつもりだったのに、画像はスケッチでしたね。
(半分寝ながら書いていました)

前回のようにタイムラインを選択してスプリクトを実行すると
押し出しとしてダイアログが表示されますが、
f:id:kandennti:20190702193801p:plain

押し出しで作成したボディを選択して実行すると、ボディとして
ダイアログが表示されます。
f:id:kandennti:20190702193811p:plain

厄介ですね。この「押し出し」と「ボディ」が関係しているのは明らかなので
何とかスプリクトで取得したいところです。


ExtendFeatureオブジェクトを見てみると
Help
f:id:kandennti:20190702193833p:plain
プロパティの中にそれっぽいものがありますよね。(この辺は勘です・・・)
'body' では無く 'bodies' なのは、Fusion360は複数のプロファイルを
1コマンドで押し出すことが可能なのですが、離れたボディは別々のボディ
となる仕様なので、仮に1個ボディでも複数形での表記なのでしょう。

一応HelpにBRepLumpの説明が有りますが、押し出しに関しては
恐らく無いでしょう。
Help

bodiesプロパティを開くと 'BRapBodies' オブジェクトであることがわかります。
f:id:kandennti:20190702193847p:plain

ここもクリックして開くと、BRapBodyのコレクションだとわかります。
f:id:kandennti:20190702193854p:plain
add item count 等、馴染み深いものしかありませんね。


ここで前回のコードに追記します。

            ・・・
            #実際に選択した要素
            ent = sel.entity
            
            #押し出しで出来た全てのボディ名を追記
            bodies = ent.bodies
            for body in bodies:
                dl_msg += '\n  出来上がったボディ[{}]'.format(body.name)
            
            #情報取得
            msg = dl_msg.format(ent.name,ent.objectType)
            ・・・

実際にタイムラインの押し出しを選択した状態で、スプリクトを実行すると
f:id:kandennti:20190702193904p:plain
こんな感じで、[押し出し1]と[ボディ1][ボディ2]が関連していることを
スプリクトで取得出来る事がわかりました。
(例外処理していないので、押し出し以外で実行すると
エラーになる可能性が高いです)

API and Scriptsの覚書

APIのフォーラムで、ひょっとしたら今後利用するかも知れない
処理等、気になったトピの覚書です。(埋もれちゃうそうなので)

・validateInputs Event以外でOKボタンを制御する方法?
Solved: Is there a way to "request" a validation event? - Autodesk Community


・commandDefinition.executeの際、パラメータとして渡せる
 NamedValuesの数少ないサンプル
Solved: Re: Anti-Aliasing effect - Autodesk Community
 
 2016年当時とは言え、Ekins氏が「これしかない」って書いていたのに
Solved: Re: Script too fast for UI to keep up - Autodesk Community
 'executeImmediately' 以外にも 'CmdId' があるじゃない。


・Fusion360APIのmessageBoxは単なるテキストだけじゃなくて
 HTMLのタグが利用出来るよ ってお話
(で、Helpには記載されていないよ との事)
An undocumented? tip about UserInterface.messageBox - Autodesk Community

Fusion360スプリクト作成の取っ掛かり1

Fusion360のスプリクトを作成する際の取っ掛かりになれば、と思い少し
役立つのではないかな?と思うスプリクトを作成しました。(後ほど)


スプリクト(やアドイン)のサンプルは結構多く見付かります。代表的なものは
公式Helpのものです。
Help

全てを見た訳では無いので断言出来ませんが、ほとんどが点・線・面等を
新たに作成するようなものばかりです。これらのサンプルの様に
"新たな要素の作成" は、比較的出来ます。実はスプリクト(や他のソフトのマクロ等)
では、"既存の要素の情報を取得する" 事の方が遥かに難しいです。

例えば「押し出し」について調べたいとします。
最初の段階として "押し出しって何オブジェクトなの?" となるのですが
こちらから探し出すのは現実的とは思えないのが本音です。
https://help.autodesk.com/cloudhelp/ENU/Fusion-360-API/images/Fusion.pdf

"押し出しってExtendFeatureオブジェクトなんだな" とさえわかってしまえば、
こちらを調べてば良いことがわかります。
Help
細かな事はわからなくても(僕もわかっていないのです)きっと押し出しに
関する情報はどれかのプロパティに含まれているはずです。

この "XXって何オブジェクトなの?" を調べるだけの為のスプリクトを
作ってみました。

#FusionAPI_python SelectItemInfo
#Author-kantoku
#Description-事前選択されている要素のオブジェクト名を表示

import adsk.core, adsk.fusion, traceback

def run(context):
    ui = adsk.core.Application.cast(None)
    try:
        #fusion360の取得
        app = adsk.core.Application.get()
        ui  = adsk.core.UserInterface.cast(app.userInterface)
        
        #選択機能
        sels = adsk.core.Selections.cast(ui.activeSelections)
        
        #未選択を除外
        if sels.count < 1:
            ui.messageBox('要素を選択してから実行してください')
            return
        
        #ダイアログ用準備
        dl_msg = '選択要素名: {}\nオブジェクト名: {}'
        dl_title = '選択要素情報'
        dl_btn = adsk.core.MessageBoxButtonTypes.YesNoButtonType
        dl_icn = adsk.core.MessageBoxIconTypes.InformationIconType
        dl_no = adsk.core.DialogResults.DialogNo
        
        #選択されているものをループ
        for i,sel in enumerate(sels):
            
            #実際に選択した要素
            ent = sel.entity
            
            #情報取得
            msg = dl_msg.format(ent.name,ent.objectType)
            if i+1 != sels.count:
                msg += '\n残りの要素も続けますか?({}/{})'.format(i+1,sels.count)
            else:
                msg += '\nこれで終了です({}/{})'.format(i+1,sels.count)
                
            #情報表示
            print(msg)
            if ui.messageBox(msg,dl_title,dl_btn,dl_icn) == dl_no:
                break #ループから抜ける
            
    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

どうしても上手く行かない為(選択フィルタの関係上)、事前に調べたい要素を
選択した上でスプリクトを実行する必要があります。

実際に試してみます。
こんな感じのデータを用意しました。
f:id:kandennti:20190702002050p:plain
スケッチに丸を描き、押しただけです。このデータのタイムラインの2個を
選択した後、先程のスプリクトを実行します。するとこんなダイアログが表示されます。
f:id:kandennti:20190702002324p:plain
これであれば、"何のオブジェクトを調べれば良いのか?" がわかると思います。
(画像の例では ”adsk::fusion::Sketch” と表示されるので、sketchオブジェクトを
 調べれば良い事がわかります)

本当は事前選択じゃなくしたいのですが、現状の選択フィルタでは作れそうに無いですね…。