Product内のCATPartをSTLファイルで出力|CATIAマクロの作成方法

今回の記事はマクロ案募集でいただいた内容です。
送って頂いた内容は以下のようなマクロです。

ワークベンチ: アセンブリデザイン

マクロ案: 
Product内のパートファイルを、 STL形式でエクスポートする実はこちらのWebにアップされている
「Product内のパートファイルを、 STP形式でエクスポートする」のプログラムを自分で編集してSTL形式でエクスポートしてみようとしたところ「コンテキストで編集中はSTLとして保存できません」というメッセージが出てきてしまい変換ができなかったのですが何か良い方法をご存じないでしょうか。

本サイトでは「IGESファイルで出力」「STEPファイルで出力」の2パターンのファイルで出力するマクロの紹介をしています。基本的にはどちらも同じコードで、コード内の拡張子部分さえ書き換えればそれぞれのファイルで出力することができるようなコードになっています。

ただ「STLファイル」の場合は同じ方法では書き出すことができません。
そのためここでは、上記リンク先のサンプルマクロを書き換え、Product内のPartファイルをSTLファイルとして出力するためのマクロを紹介します。

 

マクロの機能

今回作成したマクロはCATPartをSTLファイル(拡張子.stl)として出力するマクロです。

具体的な機能は以下のとおりです。

  マクロの機能まとめ ・選択したProduct内にあるCATPartをすべてSTLファイルとして出力
・CATPartを選択した場合はそのCATPartのみをSTLファイルとして出力
・ファイル名は「各CATPartのパーツ番号.stl」
・マクロ実行後にデスクトップに新規作成される「STL書き出し 日時」フォルダに出力
・出力後はフォルダを開く

※注意点
設計モードなっているCATPartのみ対応
・「STL書き出し 日時」と同名のフォルダがデスクトップにある場合はマクロ中断
 (日時には現在の「年/月/日/時/分/秒」が入力されるため、同名フォルダは存在しないはず )

上記の注意点にも書かれているとおり設計モードのCATPartのみ出力することができます。
表示モードになっているCATPart出力処理が無視されるので注意して下さい。
(上画像の場合「Part2.CATPart」のみ表示モードになっています)

 

サンプルコード

マクロのコードは以下のとおりです。
マクロ実行後に選択したProduct以下にあるCATPartをすべてSTLファイルとして出力します。
実行後にマクロの操作をキャンセルしたい場合は[Esc]キーを押下してください。

※コピペで実行可能ですが、保存場所のパスだけは自身の環境に合わせて書き直す必要あり
下記コード60行目の"SavePath"の中身を自身の環境に合わせて書き換えないと、
85行目の「Set CreateFold = FileSys.CreateFolder(FoldPath)」でエラーが発生するので注意。

Option Explicit

Sub CATMain()
    
  'アクティブドキュメント確認
    If TypeName(CATIA.ActiveDocument) <> "ProductDocument" Then
       MsgBox "このマクロはProductDocument専用です。" & vbLf & _
              "アセンブリーワークベンチに切り替えて実行してください。"
       Exit Sub
    End If
    
    Dim ProDoc As ProductDocument
    Set ProDoc = CATIA.ActiveDocument
    
    
'*********************************************
'          Product選択
'*********************************************

    Dim sel 'As Selection
    Set sel = ProDoc.Selection
    sel.Clear
    
    Dim Filter
    Filter = Array("Product")
    
    Dim msg As String
    msg = "Productを選択してください。"
    
    Dim Status As String
    Status = sel.SelectElement2(Filter, msg, False)
    If Status <> "Normal" Then
        MsgBox "キャンセルします。"
        Exit Sub
    End If
    
  'ユーザーが選択したProduct以下にあるPartを全て取得
    sel.Search ("プロダクト・ストラクチャー.パーツ,sel")
    If sel.Count = 0 Then
        MsgBox "選択したProduct内にPartは存在しません。"
        Exit Sub
    End If
    
    Dim i As Integer
    Dim Parts As Collection
    Set Parts = New Collection
    
    For i = 1 To sel.Count
        Parts.Add sel.Item(i).Value
    Next i
    sel.Clear
    
    
'*********************************************
'         書き出し用フォルダ作成
'*********************************************[

  '保存場所のパスを入力 ※必ず自分の環境のものに書き換えて下さい
    Dim SavePath As String
    SavePath = "C:\Users\ユーザー名\Desktop"
    
  '作成するフォルダ名を指定
    Dim FoldName As String
    FoldName = "STL書き出し " & Year(Date) & Month(Date) & Day(Date) & _
                Hour(Time) & Minute(Time) & Second(Time)
    
  '新規フォルダのパス作成
    Dim FoldPath As String
    FoldPath = SavePath & "\" & FoldName                                                             '"
    
  '同名フォルダの存在を確認
    Dim FileSys 'As FileSystem
    Set FileSys = CATIA.FileSystem
    
    Dim FoldExi As Boolean
    FoldExi = FileSys.FolderExists(FoldPath)
    If FoldExi = True Then
        MsgBox "予期せぬエラーが発生しました。" & vbLf & _
               "再度マクロを実行し直してください。"
        Exit Sub
    End If
    
  'フォルダ作成
    Dim CreateFold As Folder
    Set CreateFold = FileSys.CreateFolder(FoldPath)
    
    
'*********************************************
'              STL出力
'*********************************************
    
  'ループが終わるまで画面更新と確認メッセージの表示を一時的に行わない
    CATIA.RefreshDisplay = False
    CATIA.DisplayFileAlerts = False
    
    Dim PartDoc As Document
    Dim cnt As Integer
    For i = 1 To Parts.Count
        
        On Error Resume Next
        
      '条件分岐:Partのパーツ番号が""でない場合(=設計モードの場合)
        If Parts.Item(i).PartNumber <> "" Then
        
          'ProductをPartDocumnet(CATPart)に変換
            Set PartDoc = Parts.Item(i).ReferenceProduct.Parent
            On Error GoTo 0
        
          'CATPartのフルパスを取得
            Dim PartPath As String
            PartPath = PartDoc.FullName
        
          'CATPartを開く
            Dim OpenPart As Document
            Set OpenPart = CATIA.Documents.Open(PartPath)
        
          'STL形式で出力
            OpenPart.ExportData FoldPath & "\" & PartDoc.Part.Name & ".stl", "stl"                   '"
            
          'CATPartを閉じる
            OpenPart.Close
            
            cnt = cnt + 1
        
        End If
        
    Next i
    
    CATIA.RefreshDisplay = True
    CATIA.DisplayFileAlerts = True
    
  'STLファイルを出力したフォルダを開く
    If cnt <> 0 Then
        Shell "C:\Windows\Explorer.exe " & FoldPath, vbNormalFocus
    Else
        MsgBox "STL出力するPartを設計モードに切り替えて再度実行して下さい。"
    End If

End Sub

 

コード解説

アクティブドキュメントの定義

  'アクティブドキュメント確認
    If TypeName(CATIA.ActiveDocument) <> "ProductDocument" Then
       MsgBox "このマクロはProductDocument専用です。" & vbLf & _
              "アセンブリーワークベンチに切り替えて実行してください。"
       Exit Sub
    End If
    
    Dim ProDoc As ProductDocument
    Set ProDoc = CATIA.ActiveDocument

まずはじめにアクティブドキュメントの定義をします。
今回のマクロはCATProductでのみ有効なものなので、アクティブドキュメントがCATProduct以外の場合はTypeName関数を使った条件分岐でマクロを終了するようにしています。

条件分岐の先、つまりはアクティブドキュメントがCATProductの場合は変数「ProDOC」にアクティブドキュメントを代入します。
 

ユーザー選択のProduct内にあるすべてのPartを取得

    Dim sel 'As Selection
    Set sel = ProDoc.Selection
    sel.Clear
    
    Dim Filter
    Filter = Array("Product")
    
    Dim msg As String
    msg = "Productを選択してください。"
    
    Dim Status As String
    Status = sel.SelectElement2(Filter, msg, False)
    If Status <> "Normal" Then
        MsgBox "キャンセルします。"
        Exit Sub
    End If
    
  'ユーザーが選択したProduct以下にあるPartを全て取得
    sel.Search ("プロダクト・ストラクチャー.パーツ,sel")
    If sel.Count = 0 Then
        MsgBox "選択したProduct内にPartは存在しません。"
        Exit Sub
    End If
    
    Dim i As Integer
    Dim Parts As Collection
    Set Parts = New Collection
    
    For i = 1 To sel.Count
        Parts.Add sel.Item(i).Value
    Next i
    sel.Clear

次にユーザーが選択したProduct内にあるPartをすべて取得していきます。(最終的にはループ文を使って、ここで取得したPartを1つずつSTLファイルに出力していくという処理を行います。)

まずは「Selectionオブジェクト」のSelectElement2メソッドを使って任意のProductを選択状態にします。つぎに同オブジェクトの「Searchメソッド」を使って選択状態にしたProduct内にあるPartノードをすべて選択状態にします。

これでユーザーが選択したProduct内にある、すべてのPartノードが選択状態となります。
※このとき選択状態のCATPartの数が0個の場合にはマクロを中断するよう条件分岐をさせます。

最後に現在選択中のPartノードを「Parts」というコレクションに格納しておきます。
この操作を行う理由は選択しているオブジェクトを一時保管する方法を参照下さい。
 

書き出し用のフォルダを作成

  '保存場所のパスを入力 ※必ず自分の環境のものに書き換えて下さい
    Dim SavePath As String
    SavePath = "C:\Users\ユーザー名\Desktop"
    
  '作成するフォルダ名を指定
    Dim FoldName As String
    FoldName = "STL書き出し " & Year(Date) & Month(Date) & Day(Date) & _
                Hour(Time) & Minute(Time) & Second(Time)
    
  '新規フォルダのパス作成
    Dim FoldPath As String
    FoldPath = SavePath & "\" & FoldName                                                '"
    
  '同名フォルダの存在を確認
    Dim FileSys 'As FileSystem
    Set FileSys = CATIA.FileSystem
    
    Dim FoldExi As Boolean
    FoldExi = FileSys.FolderExists(FoldPath)
    If FoldExi = True Then
        MsgBox "予期せぬエラーが発生しました。" & vbLf & _
               "再度マクロを実行し直してください。"
        Exit Sub
    End If
    
  'フォルダ作成
    Dim CreateFold As Folder
    Set CreateFold = FileSys.CreateFolder(FoldPath)

STLファイルを出力するためのフォルダを作成します。

まずは保存場所のパスを取得します。
上記のコードでは保存場所を「SavePath = “C:\Users\ユーザー名\Desktop"」
つまりはデスクトップとしています。
※再三の注意となりますがここのパスはご自身のPCのパスに書き換えて下さい。
 多くの場合、「ユーザー名」の部分を自分のものにすれば問題ないと思います。

次に、作成するフォルダの名称を指定します。
上記コードでは「STL書き出し 日時」というフォルダ名で作成しています。
(日時には現状の日時の年から秒までを取得し、その数字の羅列を入力しています。
たとえば2020年1月2日3時4分56秒の場合、「20200102030456」と入力されます。)

このようにフォルダ名を時間によって変更させることで
デスクトップ上に同じフォルダが存在しないようにしています

ただ必ずしも存在しないとは言えないので
万が一同じフォルダが存在した場合にはマクロを終了するようにしています。
フォルダの存在を確認するには「FileSystemオブジェクト」の「FolderExistsメソッド」を使います。

最後に、これまでに決めた「保存場所」と「フォルダ名」を組み合わせてフォルダを新規作成します。
フォルダの作成は「FileSystemオブジェクト」の「CreateFolderメソッド」を使って行います。

「FolderExistsメソッド」「CreateFolderメソッド」の使い方は下記ページを参照ください。

 

STLファイル出力

  'ループが終わるまで画面更新と確認メッセージの表示を一時的に行わない
    CATIA.RefreshDisplay = False
    CATIA.DisplayFileAlerts = False
    
    Dim PartDoc As Document
    Dim cnt As Integer
    For i = 1 To Parts.Count
        
        On Error Resume Next
        
      '条件分岐:Partのパーツ番号が""でない場合(=設計モードの場合)
        If Parts.Item(i).PartNumber <> "" Then
        
          'ProductをPartDocumnet(CATPart)に変換
            Set PartDoc = Parts.Item(i).ReferenceProduct.Parent
            On Error GoTo 0
        
          'CATPartのフルパスを取得
            Dim PartPath As String
            PartPath = PartDoc.FullName
        
          'CATPartを開く
            Dim OpenPart As Document
            Set OpenPart = CATIA.Documents.Open(PartPath)
        
          'STL形式で出力
            OpenPart.ExportData FoldPath & "\" & PartDoc.Part.Name & ".stl", "stl"                   '"
            
          'CATPartを閉じる
            OpenPart.Close
            
            cnt = cnt + 1
        
        End If
        
    Next i
    
    CATIA.RefreshDisplay = True
    CATIA.DisplayFileAlerts = True

今回のマクロのメインの部分の処理「STLファイル出力」をしていきます。

現在、ユーザーが選択したProduct内にあるすべてのPartが入った「Parts」コレクションがあります。ここではループ文を使って「Parts」の中身を1つずつSTLファイルとして書き出していきます。

任意のドキュメントを別ファイルとして書き出すには
「Documentオブジェクト」の「ExportDataメソッド」を使います。

  ExportDataメソッド  

Documentオブジェクト.ExportData パス,拡張子

この構文によりDocumentオブジェクトを指定した拡張子で書き出すことができます。
パスには出力先のパス(ファイル名も含む)を入力、
拡張子には出力するファイルの拡張子を入力します。
STLファイルで出力する際はIGESやSTEPファイルの時とは違い、パスに「.stl」と拡張子を付ける必要があるので注意しましょう。

ただProductDocument上で上記のコードを使ってもSTLファイルを出力することが出ませんどうやらCATIA VBAでSTLファイルとして書き出すにはアクティブドキュメントがPartDocument(CATPart)である必要がありそうです。
(確認としてProduct上で[ファイル]>[名前を付けて保存]をクリックし[ファイルの種類]を確認するとわかりますが、「.CATProduct」は「.igs」や[.stp]に切り替えることはできますが、[.stl]に切り替えることができないことがわかります)

そこで今回のコードでは以下のような処理を行います。

① Product内にあるCATPartのパスを取得する
② パスをもとにCATPartを新規ウィンドウで開く
③ CATPartをSTLファイルとして出力
④ CATPartを閉じる
⑤ Partsコレクション内のPartの数だけ①から④をループする      
 

処理の流れを見るとわかる通り、CATPartを開いては閉じ、開いては閉じを繰り返します。
そのためデータが重いProductファイルでは処理に時間がかかることが予想されます
 

icon-edit Tips  Productが設計モードか表示モードを調べる CATIA VBAでは「Productオブジェクト」の「ApplyWorkModeメソッド」を使うことで、任意のProductを設計モード/表示モードに切り替えることができます。
しかし、モードを切り替えること自体はできますが、現在のモードがどちらなのかを取得するためのプロパティ/メソッドは用意されていません。
 
ただ、専用のプロパティ/メソッドが存在しなくとも、エラーを無視する「On Error Resume Next」とプロダクトのパーツ番号を取得するための「PartNumberプロパティ」をうまく使えば現在のモードを調べることができます。(下記コード参照)

On Error Resume Next
If Productオブジェクト.PartNumber <> "" Then
      '設計モードの処理
Else
      '表示モードの処理
End If
On Error GoTo 0

 
基本的にProductにつられているPartには必ず「パーツ番号」が存在しており、「PartNumberプロパティ」を使うことでパーツ番号を取得することができます。そのため「PartNumberプロパティ」で取得した値が「""」(空白)になることはあり得ません。
 
ただ「On Error Resume Next」を使うことで、必ずしもそうであるとは言えなくなります。
表示モードのProductに「PartNumberプロパティ」を使うとエラーが発生して処理が止まってしまいますが、「On Error Resume Next」を使うことでエラーは起こさないようにすることができます。このとき「PartNumberの取得」を無視するため、実質的に取得される値は「""」(空白)となります。
 
つまり「If Productオブジェクト.PartNumber <> “" Then」という条件を使うことで、設計モード/表示モードのProductそれぞれに処理を割り振ることができるという訳です。

 
出力フォルダを表示

  'STLファイルを出力したフォルダを開く
    If cnt <> 0 Then
        Shell "C:\Windows\Explorer.exe " & FoldPath, vbNormalFocus
    Else
        MsgBox "STL出力するPartを設計モードに切り替えて再度実行して下さい。"
    End If

最後にデスクトップに作成したフォルダを「Shell関数」を使って開きます。
Shell関数についてはExcelマクロでもよく使われ、多くの解説ページがあるためここでは割愛します。

また、先のループ内でカウント変数「cnt」を使い、もしユーザーが選択したProduct内に設計モードのProductが入っていない場合には、その旨をメッセージボックスで表示するようにもしています。

 

まとめ

今回は任意のCATPartをSTLファイルとして出力するマクロについての内容でした。

STLファイルはCATProductから直接出力することができなかったため、今回のように少し無理矢理な方法で出力する必要がありそうです。(他にいい案があるかもしれませんが)

また、アクティブドキュメントがCATProductである際に、アクティブドキュメントを切り替えずにCATPartを取得し、STLとして書き出そうとしてもうまく出力することができませんでした。このことから、アクティブドキュメントがCATPartであることが前提なのかもしれません

CATIAのSTLファイルに関しては海外サイトを含めても情報が少ないので他にもい方法が隠れているかもしれません。何かいい情報があれば、ぜひお問い合わせよりご連絡下さい。
 

サンプルマクロ集に戻る
目次へ戻る

 

 CATIAマクロを本気で勉強するなら

2024年8月26日CATIA,CATIAマクロ,VBA