C#ATIA

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

Drawのテキストサイズの取得

こちらのコメント欄に書きましたが、Drawのテキストサイズの
取得方法をテストしました。
目的のバルーンをリフレームオンしたい - C#ATIA

コメント欄の記載の解釈は間違いでした・・・。
実際に確認したところ、

左右に長い引き出し線を一時的に追加し、引き出し線の先端部の
座標値を取得する事でテキストのサイズを計算させていました。
・・・こんな発想できる脳みそが凄い。

これをバルーン(バルーンも同じDrawingTextです)で試すと
残念なことにサイズが取得出来ません・・・。
理由が定かではないのですが、何故かバルーンの場合は先端の
座標値が正しく取得出来ません。困った。

Drawの文字検索

こちらの最後にDrawの文字検索は出来ない様な
書き方をしました。
目的のバルーンをリフレームオンしたい - C#ATIA
調べてみると、機能がありました・・・。


Draw時のみメニューに追加されていました。
あまりに使わない機能な為、気が付きませんでした。

実際に試した所、バルーンや寸法・テーブルには反応せず、
テキストのみでした。
しかも選択済みのようなオレンジに反応するだけで、
見つけた文字が何処にあるのかが分かりにくい・・・。

バルーン・テーブルも検索対象でした。
”ウィンドウをリフレーム”にチェックを入れるとリフレームしました。
結果、↓悩む。

やっぱりマクロを作ります。

ExcelとCATIA V5の連携

こちらをチラッと拝見しました。
マクロで楽するCATIAテクニック① -CATPartの寸法をExcel VBAで制御する-|フルヤマモル|note

これ、恐らくExcelVBAからCATIA V5の寸法を変更させる
のだろうと思うのですが、設計テーブルで良いのでは・・・。


まぁ、それは別として

GetObject(, "CATIA.Application")

が出来るだけVBAはありがたいのですが、(pythonでの同等処理の
方法を知らない・・)これだと、最初に起動したCATIA V5しか
取得出来ないんですよね。
まぁ、それ程CATIA V5を複数起動する場面があるのか? と言われると
そんなに無い様な気もしますが。

Excel自体の複数起動は出来ない(複数ブックを開くとは別のお話です)と
思うので、CATIA V5からExcelの目的のブックを取得すれば良いだけの
はずです。間違ったブックと連帯する可能性は少ないはずです。


又、Excel->CATIA V5はアウトプロセスになる為、マクロ内で処理の多い
場合は、ちょっと遅くなります。
これも、リンク先程度の寸法変更ぐらいであれば気にならないと思い
ますが、大量に点(例えば測定結果等)や線を作りだす場合は、
個人的には結構なストレスになると思うんですけどね。
(過去の経験上大量の点を作成する方法は、CSVデータから点のみの
Igesファイルを作成し、インポートする方法です)


マクロのバックアップもCATVBAのProjectファイルだけで済むから
楽だと思うのですけどね。
某自動車メーカーさんも未だにExcel->CATIA V5なのだろうな。
ここ数年、仕事もらっていないからわからないけど。

目的のバルーンをリフレームオンしたい

何れ使うつもりなので作成しているのですが、目的のバルーンを
マクロで見つけて、リフレームオンしたいんです。

試しにコンテキストメニューを見てみると、無いです。

あまり気にしたことが無かったのですが、無いんですね。

試しに、パワー入力等を行う為の右下の部分
(名称不明・・ドキュメントには記載されているかも)

c:"コマンドID"

※ダブルクォーテーションは不要です
でコマンドを呼び出せます。

コマンドIDについては、メニューのこちらを調べるか

こちらをご覧ください。
コマンドID - C#ATIA

で、リフレームオンの言語依存無しのコマンドIDは、

CATAfrReframeOnPSOHdr

でした。

試しに、バルーンを選択した状態でリフレームオンしてみると、
(矢印部が選択済み)

ん~バルーンと言うよりバルーンが有るビューがリフレームオン
している感じです。

こんな状態でリフレームオンしても同じ状態になるので

リフレームオンが機能していないわけでは無さそうなのですが、
期待は裏切られます。
※バルーンだけではなく、線などの要素でも同じ結果でした。



仕方が無いので、マクロで

'vba
'アクティブなシートの最初のバルーンを画面中央に持ってくる

Option Explicit

Sub CATMain()
    
    Dim dDoc As DrawingDocument
    Set dDoc = CATIA.ActiveDocument

    Dim sel As Selection
    Set sel = dDoc.Selection
    
    CATIA.HSOSynchronized = False
    
    sel.Clear
    sel.Add dDoc.sheets.ActiveSheet
    sel.Search "CATDrwSearch.DrwBalloon,sel"

    Dim balloons As Collection
    Set balloons = New Collection

    Dim i As Long
    For i = 1 To sel.Count2
        balloons.Add sel.Item(i).value
    Next
    
    sel.Clear

    CATIA.HSOSynchronized = True

    ' 1個目のバルーン
    Dim balloon As DrawingText
    Set balloon = balloons.Item(1)

    ' 1個目のバルーンが画面中央になるように移動
    ' ズームはしない
    reframe_on_like_balloon balloon
    
End Sub


Private Sub reframe_on_like_balloon( _
    ByVal balloon As DrawingText)

    Dim view As DrawingView
    Set view = balloon.Parent.Parent
    
    Dim pos As Variant
    pos = Array( _
        balloon.x + view.x, _
        balloon.y + view.y _
    )

    set_view_origin pos

    CATIA.ActiveDocument.Selection.Add balloon

End Sub


Private Sub set_view_origin( _
    ByVal positionAry As Variant)
    
    Dim viewer As Variant ' SpacesViewer
    Set viewer = CATIA.ActiveWindow.ActiveViewer
    
    'http://catiadoc.free.fr/online/interfaces/interface_Viewpoint2D.htm
    Dim vp As Variant ' Viewpoint2D
    Set vp = viewer.Viewpoint2D
    
    vp.PutOrigin positionAry
    'vp.Zoom = 1#

End Sub

何とも中途半端なのですが、目的のバルーンが画面の中央なるように
画面を動かし、少しでも気が付きやすいように選択済みにして終了します。

本当はズームもしたいのですが、何を目安にどれぐらいズームすれば
良いのかが分からないのです。

せめて、この枠のサイズ等が取得出来れば良いのですが、
ちょっと見つからないです。
後はフォントのサイズと文字数、ビューとシートのスケールから
それっぽい数値を導き出すしかないのかな・・・。
キッチリしたサイズでは無くて良いのですが。

これが可能だと、重複したバルーンを見つけたり、目的のテキストを探したり
出来て便利だと思うんですけどね。
(検索だと文字での検索できないですよね?)

Drawテキストをアクティブなビューに作成する

Drawテキストをアクティブなビューに作成するサンプルです。
アイソメ図以外でも同じの為、アクティブなビューです。

'vba
'Drawのテキストを作成する

Option Explicit

Sub CATMain()

    ' 目的の文字
    Const TARGET_TEXT = "hoge"

    ' ドキュメント
    Dim doc As DrawingDocument
    Set doc = CATIA.ActiveDocument

    ' アクティブシート
    Dim sheet As DrawingSheet
    Set sheet = doc.sheets.ActiveSheet

    ' アクティブビュー
    Dim view As DrawingView
    Set view = sheet.views.ActiveView

    ' Drawのテキストの親分
    Dim drawTexts As DrawingTexts
    Set drawTexts = view.Texts

    ' 目的の文字でテキスト作成
    ' 1-目的の文字列 2-X座標 3-Y座標
    ' http://catiadoc.free.fr/online/interfaces/interface_DrawingTexts.htm
    Dim drawTxt As DrawingText
    Set drawTxt = drawTexts.Add( _
        TARGET_TEXT, _
        10, _
        20 _
    )

    ' テキストの1番目から2番目までのフォントサイズを5に変更
    ' http://catiadoc.free.fr/online/interfaces/interface_DrawingText.htm
    drawTxt.SetFontSize 1, 2, 5#

End Sub

実行結果はこの様な感じです。


逆に、テキストを選択した際のこの範囲なのですが

この座標値をマクロで取得したいのですが・・・。

何か方法があったような記憶が有るのですが、
忘れました。知りたい。

リスト内の値を連番毎にグループ分けする

やっぱり気になったので、こちらのpython版です。
配列内の値を連番毎にグループ分けする - C#ATIA

# Fusion360API Python script
# 連番をグループ化

import traceback
import adsk.core as core

def run(context):
    ui = core.UserInterface.cast(None)
    try:
        app: core.Application = core.Application.get()
        ui = app.userInterface

        lst = [1, 2, 3, 5, 6, 9, 10, 13]

        print(
            get_result_txt(
                group_by_consecutive_numbers(lst)
            )
        )

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


def group_by_consecutive_numbers(
    lst: list) -> list:

    clone = [v for v in lst]
    clone.append(-1)

    groups = []
    startIdx = 0

    for idx in range(len(clone) - 1):
        if clone[idx] + 1 != clone[idx + 1]:
            groups.append(clone[startIdx : idx + 1])
            startIdx = idx + 1

    return groups


def get_result_txt(
    lst: list) -> str:

    msgLst = []

    for ary in lst:
        if len(ary) < 2:
            msgLst.append(f'{ary[0]}')
        else:
            msgLst.append(f'{ary[0]} - {ary[-1]}')

    return '\n'.join(msgLst)

結果はこちらです。

1 - 3
5 - 6
9 - 10
13

半分どころじゃなかったですね。もうちょっと良いアルゴリズム
あるような気もしますが、基本的にVBAと同じにしています。

比較してもしょうがないのですが、
・宣言と同時に初期化
・リストの柔軟性(拡張とスライスの存在)
が大きいかな? pythonに慣れると、さすがにVBAはシンドイ・・・・。

配列内の値を連番毎にグループ分けする

今回もCATIA V5と言うよりVBAです。
何れは、前回のこちらと組み合わせて使う予定です。
配列内の重複除去した配列と重複していた値の配列の取得 - C#ATIA

具体的には、こんな感じの配列が有るとします。

(1, 2, 3, 5, 6, 9, 10, 13)

条件としては、
・ソートされている
・重複値無し(あっても良いけど・・・)

この配列を

(1, 2, 3)
(5, 6)
( 9, 10)
(13)

の様な状態にグループ分けしたいです。
”世の中、似たような事を考えている人が居るんじゃないのかな?”
と検索してみましたが、見つけることが出来ませんでした。
残念、じゃ作りましょう。

但し、欠番を確認したい気持ちで行う為、

(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15・・・)

と出力されても邪魔なだけの為、最初の配列であれば

1 - 3
5 - 6
9 - 10
13

と結果が分かれば、十分なのでこれをゴールとしたものを
作ってみました。

' vba 連番をグループ化

Option Explicit

Sub CATMain()
    
    Dim ary As Variant
    ary = Array(1, 2, 3, 5, 6, 9, 10, 13)

    Dim dict_groups As Object
    Set dict_groups = group_by_consecutive_numbers(ary)

    Debug.Print get_result_txt(get_values(dict_groups))

End Sub


Private Function group_by_consecutive_numbers( _
    ByVal ary As Variant) _
    As Object
    
    Dim size As Long
    size = UBound(ary) + 1
    ReDim Preserve ary(size)
    ary(size) = -1
    
    Dim dict_groups As Object
    Set dict_groups = CreateObject("Scripting.Dictionary")

    Dim count_groups As Long
    count_groups = 0

    Dim startIdx As Long
    startIdx = 0

    Dim finishNumber As Long
    finishNumber = UBound(ary) - 1

    Dim i As Long
    For i = 0 To finishNumber
        If ary(i) + 1 <> ary(i + 1) Then
            Call dict_groups.Add( _
                count_groups, _
                get_range_ary(ary, startIdx, i) _
            )
            
            startIdx = i + 1
            count_groups = count_groups + 1
        End If
    Next
    
    Set group_by_consecutive_numbers = dict_groups
    
End Function


Private Function get_range_ary( _
    ByVal ary As Variant, _
    ByVal startIdx As Long, _
    ByVal endIdx As Long) _
    As Variant

    Dim dict As Object
    Set dict = CreateObject("Scripting.Dictionary")

    Dim i As Long
    For i = startIdx To endIdx
        dict.Add ary(i), 0
    Next
    
    get_range_ary = dict.keys()

End Function


Private Function get_values( _
    ByVal dict As Object) _
    As Variant

    Dim ary() As Variant
    ReDim ary(UBound(dict.keys()))

    Dim key As Variant
    Dim count As Long
    count = 0
    For Each key In dict.keys()
        ary(count) = dict(key)
        count = count + 1
    Next
    
    get_values = ary

End Function


Private Function get_result_txt( _
    ByVal ary_groups As Variant) _
    As String

    Dim msg As String

    Dim i As Long
    Dim ary As Variant, count As Long
    For i = 0 To UBound(ary_groups)
        ary = ary_groups(i)
        count = UBound(ary)
        Select Case count
            Case 0
                msg = msg & ary(0) & vbCrLf
            Case Is > 0
                msg = msg & _
                    ary(0) & " - " & _
                    ary(count) & vbCrLf
        End Select
    Next
    
    get_result_txt = msg

End Function

思ったより長い・・・。

pythonだと半分以下の量で書ける気がする。