C#ATIA

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

背景色を変更・復元する

タイトルが異なりますが、こちらの続きです。
画面キャプチャをクリップボードに保存する - C#ATIA

単に背景色を切り替えるマクロです。
但し元の背景色に復元出来る様に、変更前の背景色RGBをパラメータに
保存しています。
(外部ファイルや何処かのプロパティに書き出すより、自然かと思います)

'vba sample_ChangeBackColor ver0.0.1 by Kantoku
'CATIAの背景色を変更・復元

Option Explicit

'背景色をバックアップするパラメータ名
Private Const BACKCOLOR_PRAM_NAME = "BackColorRGB"

'変更後背景色
Private Const BACKCOLOR = "255,255,255"

Sub CATMain()
    Dim Doc As Document
    Set Doc = CATIA.ActiveDocument
    
    Dim Msg As String
    
    Dim Prms As Parameters
    Set Prms = Get_Prms(Doc)
    If Prms Is Nothing Then
        Msg = "ProductかPartで使用してください"
        MsgBox Msg
        Exit Sub
    End If
    
    Msg = "背景色を変更しますか?" & vbNewLine & _
        "はい : 背景色を変更(RGB:" & BACKCOLOR & ")" & vbNewLine & _
        "いいえ : バックアップしている背景色に復元" & vbNewLine & _
        "キャンセル : 中止"
            
    Select Case MsgBox(Msg, vbYesNoCancel + vbQuestion)
        Case vbYes
            Call ChangeBackColor(Prms) '白に変更
        Case vbNo
            Call RestorationBackColor(Prms) '復元
        Case Else
            Exit Sub
    End Select
    
End Sub

'復元
Sub RestorationBackColor(ByVal Prms As Parameters)
    Dim Msg As String
    
    If Not Is_ExistsPrm(Prms, BACKCOLOR_PRAM_NAME) Then
        Msg = "バックアップしている背景色が有りませんでした"
        MsgBox Msg, vbOKOnly + vbExclamation
        Exit Sub
    End If
    
    Dim Prm As StrParam
    Set Prm = Prms.Item(BACKCOLOR_PRAM_NAME)
    
    If Not Is_RGB_Str(Prm.Value) Then
        Msg = "バックアップしている背景色パラメータが不正です"
        MsgBox Msg, vbOKOnly + vbExclamation
        Exit Sub
    End If
    
    Call Update_BackRGB(Prm.Value)
    
    Dim Sel As Selection
    Set Sel = CATIA.ActiveDocument.Selection
    With Sel
        .Clear
        .Add Prm
        .Delete
    End With
End Sub

'BACKCOLORに変更
Private Sub ChangeBackColor(ByVal Prms As Parameters)
    Dim Msg As String
    
    Dim Prm As StrParam
    If Is_ExistsPrm(Prms, BACKCOLOR_PRAM_NAME) Then
        Set Prm = Prms.Item(BACKCOLOR_PRAM_NAME)
        
        Msg = "既に背景色のバックアップがありますが、" & _
            "作業を続けますか?" & vbNewLine & _
            "はい : 新たにバックアップし、作業を進める" & vbNewLine & _
            "いいえ : バックアップは変更せず、作業を進める" & vbNewLine & _
            "キャンセル : 中止"
            
        Select Case MsgBox(Msg, vbYesNoCancel + vbQuestion)
            Case vbYes
                Prm.Value = Get_BackRGB_ToStr()
            Case vbNo
                '何もしない
            Case Else
                Exit Sub
        End Select
    Else
        Set Prm = Prms.CreateString(BACKCOLOR_PRAM_NAME, "")
        Prm.Value = Get_BackRGB_ToStr()
    End If
    
    Call Update_BackRGB(BACKCOLOR)
    'Prm.Hidden = True '非表示
End Sub


' --- サポート関数 ---
Private Function Is_RGB_Str(ByVal Str As String) As Boolean
    Is_RGB_Str = False
    
    Dim Ary As Variant
    Ary = Split(Str, ",")
    If Not UBound(Ary) = 2 Then Exit Function
    
    Dim i As Long
    For i = 0 To 2
        If Not IsNumeric(Ary(i)) Then Exit Function
        If Not Ary(i) = CLng(Ary(i)) Then Exit Function
    Next
    
    Is_RGB_Str = True
End Function

Private Sub Update_BackRGB(ByVal RGB_Str As String)
    Dim VisSetAtt As VisualizationSettingAtt
    Set VisSetAtt = CATIA.SettingControllers.Item( _
        "CATVizVisualizationSettingCtrl")
        
    Dim Rgb As Variant
    Rgb = Split(RGB_Str, ",")

    Call VisSetAtt.SetBackgroundRGB(Rgb(0), Rgb(1), Rgb(2))
    VisSetAtt.SaveRepository
End Sub

Private Function Get_BackRGB_ToStr() As String
    Dim VisSetAtt As VisualizationSettingAtt
    Set VisSetAtt = CATIA.SettingControllers.Item( _
        "CATVizVisualizationSettingCtrl")
    
    Dim ActColor(2) As Long
    Call VisSetAtt.GetBackgroundRGB( _
        ActColor(0), ActColor(1), ActColor(2))
    
    Get_BackRGB_ToStr = Join( _
        Array(ActColor(0), ActColor(1), ActColor(2)), ",")
End Function

Private Function Init_Prm(ByVal Prms As Parameters, _
                          ByVal Name As String) As Parameter
    Set Init_Prm = Prms.CreateString(BACKCOLOR_PRAM_NAME, "")
End Function

Private Function Is_ExistsPrm(ByVal Prms As Parameters, _
                              ByVal Name As String) As Boolean
    Dim Prm As Parameter
    
    On Error Resume Next
        Set Prm = Prms.Item(Name)
    On Error GoTo 0
    
    Is_ExistsPrm = Not (Prm Is Nothing)
    
    If Not TypeName(Prm) = "StrParam" Then
        Is_ExistsPrm = False
        '文字型タイプじゃない同一名のパラメータがある- 未対応
    End If
End Function

Private Function Get_Prms(ByVal Doc As Document) As Parameters
    Set Get_Prms = Nothing
    Select Case TypeName(Doc)
        Case "ProductDocument"
            Set Get_Prms = Doc.Product.Parameters
        Case "PartDocument"
            Set Get_Prms = Doc.Part.Parameters
    End Select
End Function

定数 "BACKCOLOR_PRAM_NAME" と同一名の文字型以外のパラメータが存在していると
上手く行かないです・・・。(対応策を深く考えませんでした)

又、KCLを利用しなかったのでDocumentのチェックがやや甘めです。

変更・復元を一つのマクロ(最初のMsgboxで切り替え)で行っている為、
使い勝手がイマイチなのですが、ブログでFormのコードをUp出来ないので
ご勘弁を。

正直な所、このようなマクロよりキャプチャをジャンジャン作るマクロの方が、
効率が良い気がするのですが・・・。

例えば、データをズーム・スピンさせながら、スペースキーを押すたびに
キャプチャファイルを作る とか、
スペースキーを押すたびにExcelにキャプチャを貼り付けるとか・・・。
(当方Excelが古いため試せませんが、ひょっとしたらCATIAから
Excel操作できるのかな?)

バインディングに苦しむ

昔、挑戦していた時もこれに悩まされてました。
XAMLデザイナでViewModelが存在しないと言われた場合のメモ - いろいろ備忘録日記

現象は同じだけど、プロジェクトはネットワークドライブじゃ無くCドライブ。
ひょっとしたらバインディングをコードビハインドすれば
解決するかも知れないけど、XAML側で行いたい。

全然進まない・・・。

画面キャプチャをクリップボードに保存する

「CATIAで背景色を白にした状態で、画面のキャプチャをクリップボードに取得したい」
と相談を頂きました。

クリップボードではなく、ファイルとしてであればこちらの方法がお手軽かと
思います。
背景の設定を維持しつつ背景を白でキャプチャを行う | PLM Tips Magazine

'vba sample_Capture2Clipboard ver0.0.1 by Kantoku
'CATIAのキャプチャをクリップボードに保存

'--- WinAPI ---
'capture - https://qiita.com/nezuq/items/95cad79d9a9dd920d30e
#If VBA7 And Win64 Then
    Private Declare PtrSafe Sub keybd_event Lib "user32" ( _
    ByVal bVk As Byte, _
    ByVal bScan As Byte, _
    ByVal dwFlags As Long, _
    ByVal dwExtraInfo As Long)
#Else
    Private Declare Sub keybd_event Lib "user32" ( _
    ByVal bVk As Byte, _
    ByVal bScan As Byte, _
    ByVal dwFlags As Long, _
    ByVal dwExtraInfo As Long)
#End If

Const VK_SNAPSHOT = &H2C             '[PrintScrn]キー

Const KEYEVENTF_EXTENDEDKEY = &H1    'キーを押す
Const KEYEVENTF_KEYUP = &H2          'キーを放す

'wait
#If VBA7 Then
    Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal ms As LongPtr)
#Else
    Private Declare Sub Sleep Lib "kernel32" (ByVal ms As Long)
#End If

'--- 設定 ---
'キャプチャ時の背景色 RGB
Private Const BACKCOLOR = "255,255,255"

'キャプチャ取得待ち時間 ここの時間は調整してください
Private Const WAITTIME = 200

Option Explicit

Sub CATMain()
    '現在の背景色
    Dim VisSetAtt As VisualizationSettingAtt
    Set VisSetAtt = CATIA.SettingControllers.Item("CATVizVisualizationSettingCtrl")

    Dim ActColor(2) As Long
    Call VisSetAtt.GetBackgroundRGB(ActColor(0), ActColor(1), ActColor(2))
    
    '背景色変更
    Dim rgb As Variant
    rgb = Split(BACKCOLOR, ",")

    Call VisSetAtt.SetBackgroundRGB(rgb(0), rgb(1), rgb(2))
    VisSetAtt.SaveRepository
    
    If MsgBox("キャプチャしますか?", vbYesNo + vbInformation) = vbYes Then
        Call Sleep(WAITTIME)
        Call Exec_Capture 'キャプチャ
    End If
    
    '背景色を戻す
    Call VisSetAtt.SetBackgroundRGB(ActColor(0), ActColor(1), ActColor(2))
    VisSetAtt.SaveRepository
End Sub

'キャプチャ
Private Sub Exec_Capture()
    AppActivate CATIA.Caption, True
    
    keybd_event &HA4, 0&, &H1, 0&
    keybd_event vbKeySnapshot, 0&, &H1, 0&
    keybd_event vbKeySnapshot, 0&, &H1 Or &H2, 0&
    keybd_event &HA4, 0&, &H1 Or &H2, 0&
End Sub

32bitでも対応できるようにしたつもりですが、試す環境が無い為
未テストです。

WinAPIでPrintScrnキーを押しているのですが、タイミングが難しく
確認用のダイアログを出したり、ウェイトしたりしてます。
環境によってはダイアログの残像が残ってしまう可能性があるため、

Private Const WAITTIME = 200

の数値を修正して頂く必要があるかもしれません。
f:id:kandennti:20171114155030p:plain

又、最初に紹介した方法では、アクティブなウィンドウをキャプチャしたファイルが出来上がるのに
対して、このマクロではCATIA全体のキャプチャになってしまう為、イマイチです。
(ウィンドウハンドルとか取得すれば何とかなるのかな?)

CATIAのマクロをDotNetで作る事をオススメしない理由

MVVMお勉強中ですが、イヤになってきたので久々にC#でCATIAの
マクロをちょっと作ろうかなぁ と思ったのですが、諦めました。

何時かは書こうかと思っていたので、折角の機会なので。

1.マクロの記録が取れない

結構重要です。 個人的には各コマンド類(~Factory.AddNew~メソッド類)
や検索キーワード(Selection.Search "~")等は、イチイチ覚えていません。
必要な時に記録を取って、必要な部分だけ(大半が2行)コピーし後は
捨てています。こちらのマクロを作ったのは、その為です。
GrabCAD - CAD library


2.参照設定がシンドイ

こちらでは参照設定の方法を記載しましたが
DotNetでCATIA V5のマクロを作成する際の準備 - C#ATIA

こちらのコメント部に、imihitoさんアドバイスを頂きました。
Excelフォームボタンからマクロの起動 (未確認) - C#ATIA

CATIAっぽい全てのものを設定する必要は無いのですが、
結果的に何の参照が不足しているのかわからず、VBエディターを
開き、オブジェクトブラウザで該当するファイルを調べまくっている
と言うのが本音です。

3.デバッグが辛い

IDEを利用する利用の1つが、デバッグの行いやすさじゃないかと
思います。(インテリセンスもあるかもしれませんが)
個人的にはローカルウィンドウが重要で、変数の中身の状態が確認出来る
だけではなく、プロパティ類の中身をさかのぼって確認出来る点は
非常にありがたく、未知のオブジェクトを調べる際はかなり重宝します。
ところが、C#(DotNet)ではダメなんです。

こちらはVBAで"形状セット1"を選択した状態です。
f:id:kandennti:20171103175501p:plain
スケッチやジオメトリ(点・線・面)等も確認可能ですし、Parentをさかのぼって
行けばPartやPartDocumentも取得可能です。
(Documentが取得できれば、大半 事が足ります)

一方、C#の場合はこちら。
f:id:kandennti:20171103175513p:plain
"形状セット1"の名前すら確認出来ない状態です。 種類の部分は
”MECMOD.HybridBod{System.__ComObject}”と表示されていますが
これは形状セットとわかっている為、キャストした状態だからです。
キャストしないとこんな感じです。
f:id:kandennti:20171103175523p:plain
"INFITF.CATBaseDispatch" じゃ何だかわからないです。

GetTypeメソッドを利用しても

{Name = "__ComObject" FullName = "System.__ComObject"}

と返って来るだけ。 COMオブジェクトだってことは、GetTypeする前から
知ってます・・・。

COM相互運用が原因だとはわかっているのですが、
「動くようにしましたよ」ってだけで同等ではないです。

4.CATSafeArrayVariantが機能していない(と思った)

今日わかったのがこれです。これが書きたかったんです。

"CATSafeArrayVariant" は、点の座標値等受け取る際のもので
Variant配列です。 単純に面を選択し重心を所得する
VBAのコードです。

'vba using-'KCL0.0.12'
Sub CATMain()
    If Not CanExecute("PartDocument") Then Exit Sub
    
    Dim msg$: msg = "面を選択"
    Dim elm As SelectedElement
    Set elm = KCL.SelectElement(meg, "Face")
    If elm Is Nothing Then Exit Sub
    
    Dim doc As PartDocument
    Set doc = elm.Document
    
    Dim ref As Reference
    Set ref = elm.Reference
    
    Dim spa_wb As Object
    Set spa_wb = doc.GetWorkbench("SPAWorkbench")
    
    Dim mes As Variant 'Measurable
    Set mes = spa_wb.GetMeasurable(ref)
    
    Dim cog(2) As Variant 'これが CATSafeArrayVariant
    Call mes.GetCOG(cog)
    
    Debug.Print "重心 : "; Join(cog, ",")
End Sub

最後の方の "cog(2)" が、"CATSafeArrayVariant"です。
取得する際のGetCOGメソッドは、Measurableオブジェクトですが、
正しく型指定するとエラーになります。
(この手の、処理結果を引数のVariant配列に返す、悪魔仕様の
 ものは大半が型指定するとエラーになります)

同様の処理をC#でさせます。
(コードが長くなりすぎる為、例外処理はほぼしてません)

//cs ↓これらの参照設定必要です
using System.Runtime.InteropServices;
using INFITF;
using MECMOD;
using SPATypeLib;

    class Program
    {
        static void Main()
        {
            //モロモロ
            var cat = (INFITF.Application)Marshal.GetActiveObject("CATIA.Application");
            var doc = cat.ActiveDocument as MECMOD.PartDocument;

            //選択
            var msg = "面を選択";
            var sel = doc.Selection;
            var cancel_code = new string[] { "Cancel", "Undo", "Redo" };
            var filter = new object[] { "Face" };

            sel.Clear();
            string res = sel.SelectElement2(filter, msg, false);
            if (cancel_code.Any(x => x.ToString() == res)) { return; }

            var face_ref = sel.Item2(1).Reference;

            //SPAWorkbench
            var SpaWB = doc.GetWorkbench("SPAWorkbench") as SPAWorkbench;
            if (SpaWB == null) { return; }

            //Measurable
            var mes = SpaWB.GetMeasurable(face_ref);

            //重心
            var cog = new object[3];
            mes.GetCOG(cog);

            Console.WriteLine(string.Format(
                "重心 : {0},{1},{2}", cog[0], cog[1], cog[2]));
            Console.ReadKey();
        }
    {

VBAのVariant配列は、C#の場合object配列です。 これ

            mes.GetCOG(cog);

ここでエラーになる予定だったのですが、正しく処理してます・・・。
不安定ですね・・・。本当は

            var mes_oj = mes as object;
            mes_oj.GetCenter(cog);

だと、型付けが邪魔で出来ないから

            dynamic mes_oj = mes as object;
            mes_oj.GetCenter(cog);

にしたけど、やっぱりエラーになるよ って書きたかったのですけどね。

こちらでも機能してないって書いてあるんですけど。
http://www.coe.org/p/fo/st/per=10&sort=0&thread=24278&p=1




他にも 
C#だと "遅い" → どうでも良いです。
DLL化すれば同レベルで処理します。(要レジストリに登録ですが)

C#だと配布しやすい → catvbsやvbsでも同様です。

・catvbsやvbsだとソースコード見られちゃう
  → CATVBAでパスワード付けるか。
 vbsを暗号化
VBScriptの暗号化 | VBScript さんま屋


・他言語熟知者にとってのVBAの学習コスト 
  →VBA異質だから、結構納得。

検索すると結構 "PythonでCATIAのマクロ" がHitするのですが、
動的型付け言語の方がC#より向いている気がします。

現状、DotNetで作る価値が見つかりませんね。

※追記です
GetCOGのパラメータです。
f:id:kandennti:20171106092508p:plain
配列としか出ていませんでした。

「簡単」すら難しい

過去に社内で使うものはWPFを素のままで作成しましたが、しんどいので
Prismを利用する事にしました。
基本的なサンプルから練習しようとこちらのサイトを参考にさせてもらいました。

簡単MVVM入門 with Prism - Qiita

個人的には、「簡単」すら難しかったです・・・。


VS2017 Community で行っていますが、NuGetパッケージマネージャーは改めて
インストールする必要は無かったです。

「Prism Template Pack」ではなく、NuGetの方の「Prism v5.0.0」です。 
僕が行った際、ターゲットフレームワークは 「.NET Framework 4.0」では、
「Prism.Composition」だけが、インストール出来ませんでした。(悩みました)
最低でも 4.5 は必要なのではないか? と思われます。


まず新規に作成する際、Prismのテンプレートではないです。(ここでも悩みました)
素の「WPFアプリ」から作成し、名前空間の記載から恐らくソリューションの状態は
各フォルダ毎に分けているっぽいので、こんな感じです。
f:id:kandennti:20171102143930p:plain

最後の部分ではViewについてはサラッとしか記載されていないのですが、
こんな感じで動きました。(恐らくPrismには無関係だからでしょう)

xaml

<!-- xaml View/View.xaml -->
<Window x:Class="Calclator.View.View"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Calclator.View"
        mc:Ignorable="d"
        Title="View" Height="140" Width="240">
    
    <Grid>
        <TextBox 
            x:Name="textBox" HorizontalAlignment="Left" Height="25" 
            Margin="10,10,0,0" TextWrapping="Wrap" Text="{Binding Path=X}" 
            VerticalAlignment="Top" Width="120"/>
        
        <TextBox 
            x:Name="textBox_Copy" HorizontalAlignment="Left" Height="25" 
            Margin="10,40,0,0" TextWrapping="Wrap" Text="{Binding Path=Y}" 
            VerticalAlignment="Top" Width="120"/>
        
        <TextBox 
            x:Name="textBox_Copy1" HorizontalAlignment="Left" Height="25" 
            Margin="10,70,0,0" TextWrapping="Wrap" Text="{Binding Path=Ans}" 
            VerticalAlignment="Top" Width="120"/>
        
        <Button 
            x:Name="button" Content="Button" HorizontalAlignment="Left" 
            Margin="140,10,0,0" VerticalAlignment="Top" Width="75" 
            Command="{Binding calcCommand}"/>
    </Grid>
</Window>

答えがTextBoxで良いのかな? とか有りますが、元の記載に合わせました。

コードビハインド側

//cs View.xaml.cs
using System.Windows;
using Calclator.ViewModel;

namespace Calclator.View
{
    /// <summary>
    /// View.xaml の相互作用ロジック
    /// </summary>
    public partial class View : Window
    {
        public View()
        {
            InitializeComponent();
            this.DataContext = new ViewModels();
        }
    }
}

テンプレートで出来あがるXAMLは削除した為、起動時にView.xamlが表示されるように
App.xaml(エントリーポイント?)も修正。

<!-- xaml App.xaml -->
<Application x:Class="Calclator.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:Calclator"
             StartupUri="View/View.xaml">
    
    <Application.Resources>
         
    </Application.Resources>
</Application>

何で、C#はこんなにコード書かなきゃいけないんだろう?

VS2017

社内で利用する為のツールを作らなきゃならないと思いつつ
数年経ってしまっているのですが、気が重いです。

目的のものはGUIが必要なのですが、個人的に非常に苦手です。

本来であれば、勉強ついでにPythonで と思っていたのですが
GUIが必要となるとC#の方が楽な気がして、仕方無しに
VS2017 Communityエディションをインストールしました。

何もかも忘れてます。 困ったな・・・。

ボディをかき集める

Fusion360と他のCADを併用されている方いらっしゃいますか?

Fusion360は色々なフォーマットのデータを読み込んでくれるので
助かっているのですが、Fusion360上ではこんな感じで表示しているのに
f:id:kandennti:20171027193132p:plain
中間フォーマットでエクスポートしたものを、他のCADで読み込んだ際
こんな感じになってガッカリした経験は無いでしょうか?
f:id:kandennti:20171027193141p:plain
何で、色が抜けるのか? 僕、理由を知ってます。
実はデータの状態で色が抜けてしまうようです。
f:id:kandennti:20171027193149p:plain
ちょっと大げさにしましたが赤印位置にボディがあり
全てルートコンポーネント(一番トップのコンポーネント)ではない位置に
入っています。 原因はこれなんです。
(Upしたデータは、子コンポーネントに入っているような気がしてます)

色を反映させてエクスポートしたいのであれば、全てのボディを
ルートコンポーネントに移動させればOKです。
f:id:kandennti:20171027193200p:plain
これって、Tree上でD&Dをやれば済む話ではあるのですが、
対象のボディが案外Treeの深い位置にあり、数が多いと面倒なんです。

・・・そう、面倒。 なので全てのボディをかき集めるスプリクトを
作ってみました。

#FusionAPI_python
#Author-kantoku
#Description-Collect_All_Body
#アクティブなプロダクトの全てのボディをルートにかき集める

import adsk.core, adsk.fusion, traceback

def run(context):
    ui = None
    try:
        app = adsk.core.Application.get()
        ui  = app.userInterface
        
        #確認
        msg = '全てのボディをルートコンポーネントにかき集めます。\nよろしいですか?'
        title = 'ボディかき集め'
        btn = adsk.core.MessageBoxButtonTypes.OKCancelButtonType
        icon = adsk.core.MessageBoxIconTypes.QuestionIconType
        Res = ui.messageBox(msg, title, btn, icon) 
        
        if Res != adsk.core.DialogResults.DialogOK: return       
        
        #モロモロ
        product = app.activeProduct
        des = adsk.fusion.Design.cast(product)       
        
        #パラメトリックじゃないとNG
        des.designType = adsk.fusion.DesignTypes.ParametricDesignType
        
        #ルート
        root = des.rootComponent
        
        #ルート以下のコンポーネント
        cmplst = []
        cmplst = Get_Comps(root, cmplst)
        
        #全ボディコンテナ
        bdyslst = [cmp.bRepBodies for cmp in cmplst if cmp.bRepBodies.count > 0]
        
        #全ボディ
        bdylst = []
        for bdys in bdyslst:
            for bdy in bdys:
                bdylst.append(bdy)
        if bdylst.count == 0 :
            return
        
        #カットペースト
        tgtBodies = root.features.cutPasteBodies
        [tgtBodies.add(bdy) for bdy in bdylst]
        
        #おしまい
        ui.messageBox('Done')

    except:
        if ui:
            ui.messageBox('エラー\n{}'.format(traceback.format_exc()))

#全コンポーネント
def Get_Comps(comp, complst):
    occs = comp.occurrences
    
    lst = [occ.component for occ in occs]
    
    if lst.count == 0:
        return complst
    
    for cmp in lst:
        complst.append(cmp)
        Get_Comps(cmp, complst)
    return complst

Pythonまだまだ駄目だなぁ。見事に二重ループがあるし…。
こんな感じです。

本当は、CATIAのProductからPartを作るコマンドをイメージしていたのですが
異なるDocument間でどうやったらコピペ出来るのか、方法わかりませんでした。
僕はこれで事足りるんですけどね。