C#ATIA

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

「サブツリー」コマンド

マクロで「サブツリーを開く」を行いたい と御質問を頂きました。
結論を先に書くと出来なさそうです。が、その他調べた事を覚書しておきます。

今まで利用した事が無かったのですが、メニューの「表示」内に「サブツリー」が
あるのを知りませんでした。
f:id:kandennti:20180712180236p:plain
試した所、ちょっと不思議な感じがしました。

CATIAを起動し新たにPartを作成した状態では、こんな感じでグレーアウトしてます。
f:id:kandennti:20180712180244p:plain

これを利用する為には、一度コンテキストメニューの「サブツリーを開く」を実行すると
チェックが入った状態で利用できます。
f:id:kandennti:20180712180253p:plain

クリックするとチェックが外れ、全てのサブツリーウィンドウが消えます。
f:id:kandennti:20180712180317p:plain

続いて新たにPartを作ります。
最初は利用できない状態ですが、一度コンテキストメニューの「サブツリーを開く」を実行します。
ここでメニューからではなく、サブツリーウィンドウの×印をクリックし閉じます。
f:id:kandennti:20180712180337p:plain

ここでメニューを見ると、グレーアウトしてます。
f:id:kandennti:20180712180343p:plain

先程とは状態が異なります。

サブツリーウィンドウの×印をクリックした場合は、実際にウィンドウを閉じていて
メニューの「サブツリー」はサブツリーウィンドウ全てを表示/非表示操作しているのだろう
と思われます。
(最初とX印で閉じた場合、表示/非表示に関わらずサブツリーウィンドウが無い為
 コマンド自体が利用できない)

こんな制限付きの「サブツリー」コマンドであれば、こちらで利用可能です。

 '日本語
 CATIA.StartCommand ("サブツリー")
 '英語
 CATIA.StartCommand ("Sub-Trees")

但し、サブツリーウィンドウが開いていても、CATIA.Windows.Countは変化無く
実際に開かれているのか?開かれていないのか? はマクロで判断する事も
難しそうです。(WinAPIでゴリゴリなら出来そうですが)


この「サブツリー」コマンドの存在に気が付いたのは、「表示」-「コマンドリスト」です。
f:id:kandennti:20180712180357p:plain
恐らくライセンスに関係無く、アクティブなワークベンチで利用可能なコマンドのリストを
表示してくれます。
ここで表示されるものであれば StartCommand で利用可能だと思います。

StartCommand は起動している言語に依存していますが、こちらに記載した
コマンドIDを利用すれば、言語依存しないマクロが作れます。
コマンドID - C#ATIA

但し、今回の「サブツリー」コマンドについては、GrabCADにUpしたリストには
入ってませんでした・・・。

子ウィンドウの整列スタイル

御質問頂いた際、正直何のことかわかりませんでした。
が、調べたら理解できました。(最初はパターンの何か? かと思いました)

要は、ここの表示の切り替えをマクロで行いたいと言う事ですよね?
f:id:kandennti:20180712162053p:plain

'CatArrangeStyleテスト
Sub CATMain()

    Call CATIA.Windows.Arrange(CatArrangeStyle.catArrangeCascade)
    CATIA.RefreshDisplay = True
    MsgBox "CatArrangeStyle - catArrangeCascade"
    
    Call CATIA.Windows.Arrange(CatArrangeStyle.catArrangeTiledHorizontal)
    CATIA.RefreshDisplay = True
    MsgBox "CatArrangeStyle - catArrangeTiledHorizontal"
        
    Call CATIA.Windows.Arrange(CatArrangeStyle.catArrangeTiledVertical)
    CATIA.RefreshDisplay = True
    MsgBox "CatArrangeStyle - catArrangeTiledVertical"

End Sub

3つのスタイルを順番に変更します。最小化しているウィンドウは影響無いようです。
又、環境や使用方法次第ですが、RefreshDisplayを入れておかないと
スタイルの変更が間に合わない場合があるかもしれません。
(こちらで試した際、入れないと半分ぐらいしか表示しない状態で
  MsgBoxが出現しました)

データム化された要素の入っている形状セットの取得

”マクロがPCによって動くものと動かないものがある”と相談を頂きました。
状況が良くわからないので、完全な答えには辿り着けない可能性も有りますが。。。

点を選択後、点の含まれている形状セットの取得部分が問題のようです。

まず、こんなデータを用意しました。
f:id:kandennti:20180704124318j:plain
点1は通常の状態で、点2はデータム化されています。

続いてこんなマクロを作りました。

'catvba
Sub CATMain()
    Dim doc As PartDocument
    Set doc = CATIA.ActiveDocument
    
    Dim sel As Variant ' Selection
    Set sel = doc.Selection
    
    '選択
    Dim msg As String
    msg = "点を選択"
    
    Dim filter As Variant
    filter = Array("Point")
    
    sel.Clear
    Select Case sel.SelectElement2(filter, msg, False)
        Case "Cancel", "Undo", "Redo"
            Exit Sub
    End Select
    
    '選択要素の取得
    Dim point As AnyObject
    Set point = sel.Item(1).value
    
    '結果
    Debug.Print "********"
    Debug.Print "point typename : ", TypeName(point)
    Debug.Print "point.Parent typename : ", TypeName(point.Parent)
    Debug.Print "point.Parent.Parent typename : ", TypeName(point.Parent.Parent)
    Debug.Print "point.Thickness.Parent.Parent typename : ", TypeName(point.Thickness.Parent.Parent)
End Sub

点を選択し、Parentのオブジェクトタイプをイミディエイトウィンドウに表示します。
もう答えは書いているのですが・・・。

GSD要素がデータム化されている場合とされていない場合では、画面上や手動操作では
大きな違いを感じませんが、マクロではかなりの違いが有ります。

このマクロで点1を選択した際の結果はこちら

********
point typename :            HybridShapePointOnPlane
point.Parent typename :     HybridShapes
point.Parent.Parent typename :            HybridBody
point.Thickness.Parent.Parent typename :  HybridBody

質問者さんのコードでは、"point.Parent.Parent" となっており、HybridBodyが
取得できています。

続いて点2を選択した際の結果はこちら

********
point typename :            HybridShapePointExplicit
point.Parent typename :     Parameters
point.Parent.Parent typename :            Part
point.Thickness.Parent.Parent typename :  HybridBody

"point.Parent.Parent" は、HybridBodyではなくPartになります。
そもそも point.Parent が、点1では HybridShapes なのに対し
点2では Parameters になります。

データム化されている・されていないを判断し処理を分けるのも
良いかもしれませんが、共通のプロパティ Thickness を利用すると
処理を分ける必要も無さそうです。

    Dim HybrBody As HybridBody
    Set HybrBody = point.Thickness.Parent.Parent


Thicknessプロパティ は HybridShapeオブジェクトで実装されています。
以前から思うのですが、何故GSD要素に "厚み" が必要なのかな?
(ライセンス無いのでわからないのですが ボリューム?)

ファイルを最小化でオープンしつつ、オープン前のウィンドウをアクティブ化

「パワーコピーのPartファイルを最小化で開きつつ、開く前のアクティブな'ウィンドウをアクティブ状態にする」
と言う内容のご相談を頂きました。

正直な所、どのような操作を想定されているのかが、把握できていない為
目的の状態になっていない可能性もありますが・・・

'vba
Sub CATMain()
    'パワーコピーファイル パス
    Dim PowerCopy_path As String
    PowerCopy_path = "C:\temp\powercopy_part.CATPart"
    
    'パワーコピーファイル オープン前に現在のアクティブな
    'ウィンドウを取得
    Dim BeforeActWin As Window
    Set BeforeActWin = CATIA.ActiveWindow
    
    'パワーコピーファイル オープン
    Dim objPspDoc As PartDocument
    Set objPspDoc = CATIA.Documents.Open(PowerCopy_path)
    
    'パワーコピーファイル のウィンドウ
    Dim ActiveWin As Window
    'Set ActiveWin = CATIA.ActiveWindow
    Set ActiveWin = CATIA.Windows.Item(CATIA.Windows.count)
    
    '最小化
    ActiveWin.WindowState = catWindowStateMinimized
    
    '最初のアクティブなウィンドウをアクティブ
    BeforeActWin.Activate
    
    'ここで何かしらの処理
    Stop
    
    'パワーコピーファイル クローズ
    objPspDoc.Close
End Sub

・ファイルをオープンする前に、現状のアクティブウィンドウを取得しておきます。
  (Set BeforeActWin = CATIA.ActiveWindow)
・ウィンドウの最小化はWindowStateプロパティで可能です。
  (ActiveWin.WindowState = catWindowStateMinimized)

DrawingTextの中心座標

DrawingTextの中心座標を取得したい との記載を見て思い付きで書きました。
Size of the textbox on a drawing - DASSAULT: CATIA products - Eng-Tips
最初に、”遅いよ” って書いたんですけどね。

リトルクトゥルフさんがアッサリ答えを書いてくれました。
・・・やっぱりレベルが違いすぎですね。

コードが書かれていなかったので、作ってみたものの
リーダー(引き出し線)の削除でエラーになっちゃいます。

DrawingText.Leaders.Remove(0)

ん~ エラーにはなるものの削除は出来てます。
仕方ないので On Error Resume Next でエラーを回避するように
したのは良いのですが、すっきりしない。

探しまくってやっとCOEの記載を発見しました。
COE : Forums : Text box size
どうやっているのかな? と思い見てみると
やっぱり On Error Resume Next してます・・・。

僕だけじゃないようなので、すっきり。

VBA 言語環境による挙動の違い

先日のマクロですが、上手く動かないらしいのです。
draw with a catia all the Dual Geodesic Icosahedra - DASSAULT: CATIA products - Eng-Tips

原因が良くわからないのですが、CATIAのリリース違いが
影響するような程の最新の機能は使っていないはずです。

知識が無い為何とも言えないのですが、残る可能性は
言語の違いかと思っています。
マクロの内容的に、処理を速めるために正規表現を利用しているのですが
この辺がエンコードで上手く機能しないとか、エクスポートしたVBAファイル
(~.bas,~cls)が、他の言語だと文字化けし機能しないとか・・・。

何か情報をお持ちの方、教えて頂けると助かります。

Dual Geodesic Icosahedra3

こちらの続きです。
Dual Geodesic Icosahedra2 - C#ATIA

完成したので、テストデータと共にGrabCADにUpしました。
恐らく誰にも役には立たないでしょう。
3D CAD Model Collection | GrabCAD Community Library
結局一番苦労したのは、正規表記のパターンでした。
未だに宝探しをしている気分です。


面の作成に失敗していた理由がわかりました。
Visual PolyhedraのサイトにUpされている座標データの中に
こんな感じの☆型の面を、5個の頂点だけで表現している
データがあります。
f:id:kandennti:20180626165307p:plain
フィルサーフェスを利用して面を作成している為、こんな感じの自己交差
した状態ではエラーになる為、面が抜けてしまったようです。
対応策を考えるのも面倒な為、そのままにしました。

実は、こんなスケッチでもFusion360は面が作れるんですよね。
こちらでそれを利用したものを作りました。
Solved: How to remove inner sketch lines from an intersection sketch? - Autodesk Community
スケッチの考え方の違いを利用しています。


Upしたマクロファイルの "SurfaceFactory.cls" ですが(生意気なネーミングで申し訳ないのです)
このマクロだけではなく、他にも利用できるように考えて作っています。
英語じゃ書けそうになかったので、こちらで説明を。

3D点:array(double,double,double) でXYZの順です。都合上ArrayVariantです。
一枚の面:array(3D点,3D点,3D点…)です。各頂点を表す為、当然3点以上が必要です。
複数の面:array(一枚の面,一枚の面,一枚の面・・・)です。

一枚だけ面を作成したい場合は、ary(ary,・・・) な感じです。

Sub Example_Single()
    'パートドキュメント
    Dim doc As PartDocument: Set doc = CATIA.Documents.Add("Part")
    
    '座標値
    Dim pos As Variant
    pos = Array(Array(0, 0, 0), Array(1, 0, 0), Array(0, 1, 0))
    
    'SurfaceFactoryインスタンス
    Dim surfFact As SurfaceFactory: Set surfFact = New SurfaceFactory
    
    '面を作成するパートドキュメントをセット
    Call surfFact.SetPartDoc(doc)
    
    '座標値から面を作成 - 形状セットには入りません!
    '戻りは HybridShapeSurfaceExplicit
    Dim surf As HybridShapeSurfaceExplicit
    Set surf = surfFact.CreateSurf(pos)
    
    '形状セットに挿入
    Dim hBody As HybridBody: Set hBody = doc.Part.hybridBodies.Add()
    Call hBody.AppendHybridShape(surf)
    
    'インスタンス破棄 - 破棄することで内部の一時的なものを削除します。
    Set surfFact = Nothing
End Sub

複数面であれば、ary(ary(ary,・・・),・・・) な感じです。

Sub Example_Multi()
    'パートドキュメント
    Dim doc As PartDocument: Set doc = CATIA.Documents.Add("Part")
    
    '座標値郡
    Dim posary As Variant
    posary = Array( _
                Array(Array(0, 0, 0), Array(1, 0, 0), Array(0, 1, 0)), _
                Array(Array(0, 0, 0), Array(0, 1, 0), Array(-1, 1, 0)), _
                Array(Array(0, 0, 0), Array(-1, 0, 0), Array(0, -1, 0)), _
                Array(Array(0, 0, 0), Array(0, -1, 0), Array(1, -1, 0)))
    
    'SurfaceFactoryインスタンス
    Dim surfFact As SurfaceFactory: Set surfFact = New SurfaceFactory
    
    '面を作成するパートドキュメントをセット
    Call surfFact.SetPartDoc(doc)
    
    '座標値郡から面郡を作成 - 形状セットには入りません!
    '戻りは Collectiont
    Dim surfs As Collection
    Set surfs = surfFact.CreateSurfs(posary)
    
    '形状セットに挿入
    Dim hBody As HybridBody: Set hBody = doc.Part.hybridBodies.Add()
    Dim surf As HybridShapeSurfaceExplicit
    For Each surf In surfs
        Call hBody.AppendHybridShape(surf)
    Next
    
    'インスタンス破棄 - 破棄することで内部の一時的なものを削除します。
    Set surfFact = Nothing
    
End Sub

で、折れ線とフィルで作成可能な面が作れます。
その為、STLや3DDXF等のポリゴンっぽいものも、座標値配列にさえすれば
流用可能です。 恐らく使わないですが。