C#ATIA

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

DrawingTableのSetCellObjectメソッド機能していない

このメソッドです。
r1 DrawingTable (Object)

既存のテキストをテーブルのセルに突っ込んでしまいたいのですが、
エラーになります。

こんなコードを作りました。

'vba エラーになります using kcl
Option Explicit

Sub CATMain()
    
    Dim dDoc As DrawingDocument
    Set dDoc = CATIA.ActiveDocument
    
    Dim vi As DrawingView
    Set vi = dDoc.Sheets.ActiveSheet.views.ActiveView
    
    Dim tbl As DrawingTable
    Set tbl = KCL.SelectItem("テーブル選択", "DrawingTable")
    If tbl Is Nothing Then Exit Sub
    
    Dim dt As DrawingText
    Set dt = KCL.SelectItem("テキスト選択", "DrawingText")
    If dt Is Nothing Then Exit Sub
    
    tbl.ComputeMode = CatTableComputeON
    tbl.SetCellObject 1, 1, dt '←ここでエラー

End Sub

こんな感じのテーブルとテキストを用意します。
f:id:kandennti:20190222183954p:plain

マクロを実行し、テーブルを選択した後、テキストを選択します。
f:id:kandennti:20190222184151p:plain
エラーになります。
型指定を辞めたりイロイロとやったつもりなのですがダメです。

そもそもGetは兎も角Set出来るのかな? とは思っていましたよ。
手動でも出来ないから。参照先を変えてくれれば良いだけなんだけどなぁ。

もちろんSetCellStringメソッドは成功するのですが、それでは
属性リンクが無い状態なんです。

検索しても成功事例無し。「ダメだ」と言う情報すら無し。
機能しないのならHelpに載せないで欲しい。

2D属性リンクを扱いたい5 属性リンク付き座標テーブル

こちらの続きです。
2D属性リンクを扱いたい4 - C#ATIA

やっと属性リンク付き座標テーブルが出来ました。

'vba AttributeLinkTable Ver0.0.1 using-'KCL0.0.12'  by Kantoku
'属性リンク付き座標テーブル-平面上の点のみ対応

Private Const TITLE = "AttributeTable"  'テーブルのタイトル
Private Const KEY_H = "H"               'パラメータ用Hキー
Private Const KEY_V = "V"               'パラメータ用Vキー
Private Const ROWSIZE = 10              'テーブル初期行高さ
Private Const COLUMNSIZE = 35           'テーブル初期列幅

Sub CATMain()

    'ドキュメントのチェック
    If Not CanExecute("DrawingDocument") Then Exit Sub
    
    Dim dDoc As DrawingDocument
    Set dDoc = CATIA.ActiveDocument
    
    'ビュー選択
    Dim msg As String
    msg = "テーブルを作成する、ビューを選択してください /ESC-終了"
    
    Dim vi As DrawingView
    Set vi = KCL.SelectItem(msg, "DrawingView")
    If vi Is Nothing Then Exit Sub
    
    '形状セット選択
    msg = "平面上の点を含んだ、形状セットを選択してください /ESC-終了"
    
    Dim hBdy As HybridBody
    Set hBdy = SelectItem4(msg, msg, Array("HybridBody"))
    If hBdy Is Nothing Then Exit Sub
    
    'リンクPart取得
    Dim lnkPt As Part
    Set lnkPt = KCL.GetParent_Of_T(hBdy, "Part")
    If lnkPt Is Nothing Then
        MsgBox "形状セットのPartが取得できませんでした"
        Exit Sub
    End If
    
    'パラメータ名取得
    Dim prms As Variant
    prms = GetParamNames(hBdy)
    If IsEmpty(prms) Then
        msg = "処理すべき点が含まれていませんでした" & vbCrLf & _
            "(平面上の点のみ対応してます)"
        MsgBox msg
        Exit Sub
    End If
    
    'テーブル作成
    Dim tbl As DrawingTable
    Set tbl = vi.Tables.Add(0, 0, 1, 1, ROWSIZE, COLUMNSIZE) '仮
    
    'テーブルに書き込み
    Call PushData2Table(tbl, prms, lnkPt.Parameters)
    
    MsgBox "done"
    
End Sub

'テーブルに投げ込む
Private Sub PushData2Table( _
    ByVal tbl As DrawingTable, _
    ByVal pntprms As Variant, _
    ByVal prms As Parameters)
    
    'Column追加
    Dim clmcnt As Long
    clmcnt = UBound(pntprms(0))
    
    Dim c As Long
    For c = 0 To clmcnt - 1
        Call tbl.AddColumn(1)
    Next
    
    'row追加+タイトル分
    Dim rowcnt As Long
    rowcnt = UBound(pntprms)
    
    Dim r As Long
    For r = 0 To rowcnt
        Call tbl.AddRow(1)
    Next
    
    'タイトル
    Dim titles As Variant
    titles = Array(TITLE, KEY_H, KEY_V)
    
    Dim dt As DrawingText
    For c = 0 To clmcnt
        Set dt = tbl.GetCellObject(1, c + 1)
        dt.Text = titles(c)
    Next
    
    '書き出し
    For r = 0 To rowcnt
        Set dt = tbl.GetCellObject(r + 2, 1)
        dt.Text = pntprms(r)(0)
        
        For c = 1 To clmcnt
            Set dt = tbl.GetCellObject(r + 2, c + 1)
            Call dt.InsertVariable(0, 0, prms.Item(pntprms(r)(c)))
        Next
    Next
    
End Sub

'形状セット内の点からパラメータ名を取得
Private Function GetParamNames( _
    ByVal hBdy As HybridBody) As Variant
    
    Dim shps As HybridShapes
    Set shps = hBdy.HybridShapes
    
    'HybridShapePointOnPlaneのみ
    Dim lst As Collection
    Set lst = New Collection
    
    Dim shp As HybridShape
    Dim i As Long
    For i = 1 To shps.Count
        If Not typename(shps.Item(i)) = "HybridShapePointOnPlane" Then
            GoTo continue
        End If
        
        lst.Add shps.Item(i)
continue:
    Next
    
    If lst.Count < 1 Then Exit Function '点なし
    
    
    'HVパラメータ名を取得
    Dim pt As Part
    Set pt = KCL.GetParent_Of_T(hBdy, "Part")
    
    Dim prms As Parameters
    Set prms = pt.Parameters
    
    Dim ary() As Variant
    ReDim ary(lst.Count - 1)
    
    Dim baseName As String
    Dim prmH As String
    Dim prmV As String
    Dim cnt As Long
    cnt = -1
    For i = 1 To lst.Count
        baseName = prms.GetNameToUseInRelation(lst.Item(i))
        prmH = Left(baseName, Len(baseName) - 1) & _
            "\" & KEY_H & Right(baseName, 1)
        prmV = Left(baseName, Len(baseName) - 1) & _
            "\" & KEY_V & Right(baseName, 1)
        
        If ExistsParam(prmH, prms) And ExistsParam(prmV, prms) Then
            ary(i - 1) = Array(lst.Item(i).name, prmH, prmV)
            cnt = cnt + 1
        End If
    Next
    
    If cnt < 0 Then Exit Function '点なし
    
    If Not UBound(ary) = cnt Then
        ReDim Preserve ary(cnt)
    End If
    
    GetParamNames = ary
    
End Function

'パラメータ存在してる?
Private Function ExistsParam( _
    ByVal key As String, _
    ByVal params As Parameters) As Boolean
        
    Dim prm As Parameter
    
    Err.Number = 0
    On Error Resume Next
        Set prm = params.Item(key)
    On Error GoTo 0
    
    ExistsParam = IIf(Err.Number = 0, True, False)

End Function

'SelectElement4
'pram:filter-AryVariant(string)
Private Function SelectItem4( _
    ByVal msg1 As String, _
    ByVal msg2 As String, _
    ByVal filter As Variant) As AnyObject
    
    Dim sel As Variant
    Set sel = CATIA.ActiveDocument.selection
    Dim targetDoc As Variant 'Document 型指定Ng
    
    sel.Clear
    Select Case sel.SelectElement4(filter, msg1, msg2, _
                                   False, targetDoc)
        Case "Cancel", "Undo", "Redo"
            Exit Function
    End Select
    
    Dim tgtSel As selection
    Set tgtSel = targetDoc.selection
    Set SelectItem4 = tgtSel.Item2(1).Value
    
    sel.Clear
    tgtSel.Clear
End Function

対象は平面上の点のみです。
f:id:kandennti:20190221193715p:plain

まず、座標テーブルを作成するDrawと座標を取得するPartを開きます。
f:id:kandennti:20190221193724p:plain
Draw側をアクティブにしてマクロをスタート。
・まず、テーブルを作成するビューを選択。
・続いてPart側をアクティブにし、座標を取得する形状セットを選択。
で終わりです。

実行後の状態はこんな感じです。
f:id:kandennti:20190221193734p:plain
属性リンクが付いてます! ・・・どれがどのセルか分かんないのですが。
赤印部分は点の名前です。

・単位要らない : プロパティのチェックを外すのはマクロでは無理っぽいです。
・自動フィットしたい : ここもマクロでは無理っぽいです。
  f:id:kandennti:20190221193744p:plain
・フォントが気に入らない : 個人的にはSSS4にしたいのですが、客先環境では
 許されないので、デフォルトのままです。(フォント類はマクロでは修正してません)


ここがゴールじゃない上に、もう業務ではチマチマやってしまいました。
(要は間に合わなかった)
属性リンクの確認も未だやりにくいまま。
それ以上に、何でこんなにテーブルって扱いにくいんだろうとも思ってます。


タイミングが良すぎるぐらいなトピが出来ています。
Drawing text with Attribute link in VB6 - DASSAULT: CATIA products - Eng-Tips
みんな属性リンクに困っているんだな、きっと。

2D属性リンクを扱いたい4

こちらの続きです。
2D属性リンクを扱いたい3 - C#ATIA

今直ぐにでも使いたく時間かけていられない為、現状の小道具を
生かすことにします。

属性リンクを使用するのは、単なるテキストではなくテーブルなんです。
(更に一歩ハードルが高いんです)

リンク情報は前回のもの単体で取得できるので、付き合わせる為に
DrawingTable内のDrawingTextのオブジェクト名をCSVで吐き出す
マクロを作ります。

'vba using-'KCL0.0.12'  by Kantoku
'DrawTable内のDrawTxtのオブジェクト名と値を書き出す

Sub CATMain()

    'ドキュメントのチェック
    If Not CanExecute("DrawingDocument") Then Exit Sub
    
    Dim dDoc As DrawingDocument
    Set dDoc = CATIA.ActiveDocument
    
    'エクスポートパス
    '本当は一度保存しているかチェックすべき
    Dim exppath As String
    exppath = GetExpPath(dDoc.FullName)
    
    'テーブル選択
    Dim msg As String
    msg = "テーブル選択"
    
    Dim dt As DrawingTable
    Set dt = KCL.SelectItem(msg, "DrawingTable")
    If dt Is Nothing Then Exit Sub
    
    'テーブル情報
    Dim data As Variant
    data = GetTableData(dt)
    
    'エクスポート
    Call KCL.WriteFile(exppath, Join(data, vbCrLf))
    
    MsgBox "done"
    
End Sub

Private Function GetExpPath( _
    ByVal drwpath As String) As String

    Dim ary As Variant
    ary = KCL.SplitPathName(drwpath)
    
    Dim tmp As String
    tmp = ary(0) & "\" & ary(1) & "_table" & ".csv"
    
    GetExpPath = KCL.GetNewName(tmp)
    
End Function

Private Function GetTableData( _
    ByVal dt As DrawingTable) As Variant
    
    Dim rowcnt As Long
    rowcnt = dt.NumberOfRows
    
    Dim clmcnt As Long
    clmcnt = dt.NumberOfColumns
    
    Dim cells() As String
    ReDim cells(rowcnt - 1)
    Dim tmp() As String
    
    Dim i As Long, j As Long
    Dim drwtxt As DrawingText
    For i = 1 To rowcnt
        ReDim tmp(clmcnt - 1)
        For j = 1 To clmcnt
            Set drwtxt = dt.GetCellObject(i, j)
            tmp(j - 1) = "(" & drwtxt.name & ":" & drwtxt.Text & ")"
        Next
        cells(i - 1) = Join(tmp, ",")
    Next
        
    GetTableData = cells
        
End Function

本来なら行うべき細かなチェックはしてません。

実行するとDrawファイルと同じでフォルダ内に
(Drawファイル名)_table.csv
が出来上がります。

吐き出されるデータはCSVフォーマットで各セルの
(オブジェクト名 : セルの値)
なっています。

サポートさんに指摘されたのですが、このセルのオブジェクト名は
手動で確認出来ないんです。
(手動でセルのプロパティを開いても "テーブル.xx" のような表記です)
その為、リンク情報で表示される「元エレメント」の名前で検索しても
Hitしません。
f:id:kandennti:20190220190236p:plain
リンク情報見ても役に立たないんですね・・・。

出来上がった2個のCSVを付き合せて確認。人力で。
f:id:kandennti:20190220190246p:plain
どう考えても面倒です。確認出来ないよりはまだマシですが、
時間が出来たらまともな物を作成します・・・。

それ以上にリンク情報を取得するヤツが、実務データで試すとエラー
になっちゃうんです。リンクが多いとエラーになるので、恐らく
ダイアログを閉じるタイミングが早過ぎるんだろうと思うのですが。

2D属性リンクを扱いたい3

大した進展も無いまま、こちらの続きです。(忘れそうなので)
2D属性リンクを扱いたい2 - C#ATIA

こちらのC#で作ったやつ、正常に動きませんでした・・・。
3D CAD Model Collection | GrabCAD Community Library
何でだろう、と思ったのでVS立ち上げて実行したら動きました。
f:id:kandennti:20190219194451p:plain
Attributeも、ちゃんと取得出来てます。

とりあえずビルドしたらexeファイルでも動いたので、少し安心しました。
VS立ち上がる際、何かUpdateしていたのでその辺が原因だったのかも。

但し、VBAと絡めて実行する際ちょっとばかり使い勝手が悪いので
何か対策を取らないと。
3年前なのでVBAのコードもイマイチで、その分自分が成長したんだろう
と思っておきたい。

2D属性リンクを扱いたい2

こちらの続きです。
2D属性リンクを扱いたい1 - C#ATIA

属性リンクを使ったことが無い為、イロイロと確認です。

3DでXY平面状に点を作成し、2Dでテキストを作成。
属性リンクをH→X、V→Yとして作ります。
f:id:kandennti:20190219130051p:plain
属性リンクパネルの「現行の選択」は多分、インターナルネームかな?
恐らく、式で利用できるパラメータ類が使えるのだろうと思います。

3D側で数値を変え、2D側を強制更新すると反映されます。
f:id:kandennti:20190219130120p:plain
リンクしているにも関わらず、ビューのアイコンはリンクしていない
ものでも出来るので、軽く罠のような雰囲気です。
強制更新に関してはこちらが役に立ちそうです。
任意のビューのみを強制更新 - C#ATIA

編集-リンク であればリンクしていることが確認出来ますね。
f:id:kandennti:20190219130142p:plain

ここで疑問だったのが、参照しているものが削除された場合は
どうなるの? か。
f:id:kandennti:20190219130157p:plain
知らん顔してテキストはそのままなんですね。
何らかの確認方法を確立しなければならない雰囲気がヒシヒシと。
(属性リンク使わなきゃいいのに・・・)

属性リンクを作るのは、InsertVariableメソッド出来そうだな
とは感じているのですが、リンクを削除する方法が良くわからないです。
直接textプロパティを書き換えてしまう為、こんな手抜きなものを
実行します。

Sub CATMain()

    Dim dDoc As DrawingDocument
    Set dDoc = CATIA.ActiveDocument
    
    Dim txt As DrawingText
    Set txt = dDoc.Sheets.ActiveSheet.views.ActiveView.Texts.Item(1)
    
    txt.Text = "hoge"

End Sub

実行だけしてみると
f:id:kandennti:20190219130215p:plain
おーまた知らん顔してる。リンクしている要素無いのにリンクしてます
って出ちゃうんだ。属性リンクは同期しないんだなぁ。
強制更新してもダメでした。

ダブルクリック等でテキストエディターを立ち上げ終了すると
f:id:kandennti:20190219130228p:plain
無事リンクが無くなってます。

便利以上に、リスクの方が大きいように感じるんだけどなぁ。

2D属性リンクを扱いたい1

3Dのパラメータ等の値を、2Dテキストにリンクさせた状態を作る方法を
薄々は知っていたのですが、「僕には関係ない」と思い調べずにいたのですが
使用する必要性が出てきた(逃げられそうに無い)ので、重い腰を上げる事に
しました。

Helpで調べたり、頂いた資料を眺めたり、知人に相談したり、サポートに
問い合わせてみたり・・・。使い方は直ぐにわかったのですが、量が多いため
劇的にメンドクサイ。

調べてみるとマクロでも作成出来そうなことはわかりました。
あまり良いサンプルが見つからなかったのですが、
こちらでチラッと出てくる、InsertVariableメソッドがそのようです。
Macro To Add Additional Sheets to a Drawing - DASSAULT: CATIA products - Eng-Tips

これですね。
r1 DrawingText (Object)


困るのが、何処を参照しているのか? の確認方法です。
あのメソッド名からしても、戻り値で参照先を
得られそうに無いです。
他のプロパティ・メソッドでも得られそうな気がしないのですが、
どうでしょうか?

属性リンクを作ったその時は、まだ不安も無いのですが、
時間が経てば正しい参照先なのかどうか? の不安が残りませんか?

唯一確認出来そうな方法が、編集-リンクで表示されるダイアログ
のような気がするので、こちらを利用すれば可能なのかと
感じております。
3D CAD Model Collection | GrabCAD Community Library
ファイル間リンクの取得6 - C#ATIA
ファイル間リンクの取得7 - C#ATIA

届くかな?

断面図から断面を切った位置の座標値を取得

こちらでコメント頂いた
「断面図から断面を切った位置の座標値を取得」
についてです。
図面の断面のネーミング - C#ATIA


結論から書くと、取得出来そうに有りませんでした。
念のためこんな感じのコードは作りました。

'vba using-'KCL0.0.12'  by Kantoku
'断面図から断面元のビューと断面数の取得

Sub CATMain()
    'ドキュメントのチェック
    If Not CanExecute("DrawingDocument") Then Exit Sub
    
    '断面図選択
    Dim msg As String
    msg = "DrawViewを選択して下さい : ESCキー 終了"
    
    Dim secvi As DrawingView
    Set secvi = SelViewSection(msg)
    If secvi Is Nothing Then Exit Sub
    
    '断面元取得
    Dim refvi As DrawingView
    Set refvi = secvi.ReferenceView
    If refvi Is Nothing Then
        MsgBox "断面図の元のビューが取得出来ませんでした"
        Exit Sub
    End If
    
    '断面数取得
    Dim seccnt As Long
    seccnt = GetSectCount(refvi)
    
    msg = "選択ビュー:" & secvi.name & vbCrLf & _
          "断面元ビュー:" & refvi.name & vbCrLf & _
          "断面元の断面数:" & seccnt
    MsgBox msg
    
End Sub

Private Function GetSectCount( _
    vi As DrawingView) As Long
    
    CATIA.HSOSynchronized = False
    
    Dim sel As selection
    Set sel = CATIA.ActiveDocument.selection
    
    With sel
        .Clear
        .Add vi
        .Search "(CATDrwSearch.DrwCallout),sel"
        GetSectCount = .Count2
        .Clear
    End With
    
    CATIA.HSOSynchronized = True
    
End Function

Private Function SelViewSection( _
    ByVal msg) As DrawingView
    
    Set SelViewSection = Nothing
    Dim vi As DrawingView
    
Continue:
    Set vi = SelectItem(msg, "DrawingView")
    If vi Is Nothing Then Exit Function
    
    If vi.ViewType = catViewSection Then
        Set SelViewSection = vi
        Exit Function
    End If
    
    MsgBox "断面のビューを選択してください"
    GoTo Continue
End Function

断面元のビューの特定は可能ですが、断面のライン自体が取得出来ませんでした。
(Arrowは、本当に矢印の要素でした)

可能な事は、上記で示したとおり検索でヒットさせる方法ですが
ここからオブジェクトを取得しても、DrawingViewとなってしまい
実質マクロで扱うのは不可能だと判断しました。

「どうしても」となれば、3Dとのリンクを分断することで断面の線が
単なる線となる為、これを何かしらの方法で座標値を見つける事が
出来るかも知れませんが、リンクを切るのはリスクの方が大きいようにも
感じます。(マクロでUndoを行えば、戻るのは確かですが・・・)

安全を考慮してビュー自体を何処かにコピペして、分断出来れば
良いのですが、ビューのコピペでは断面の線はコピー出来ないようなので
お手上げです。