C#ATIA

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

CATPart内エラー時のUpdateObject

こちらでコメント頂いた
「GetMeasurableはUpdate出来ないと長さも取得できそうにありません」
について、解決されたようですが、試しているうちに知らなかった事に
出くわした為、記載しておきます。
選択した円弧の長さを表示1 - C#ATIA


テストしたデータはこんな感じです。
f:id:kandennti:20170621131323p:plain
データをUp出来れば良いのですが・・・
全てXY平面上にあり、線は各点を端点としています。
この状態から、点P4の座標値を(5,20,0)→(5,5,0)にマクロで変更させ
L3(P4-P5)の長さを取得します。
途中で交差(ITS)が履歴内に入っていますが、L3とは無関係です。
但し、P4の座標値を変更する事で交差がエラーとなってしまう状態です。
(要は、取得したい線とは無関係な部分でエラーが起きている状態にします)

Sub CATMain()
    '準備
    Dim Doc As PartDocument: Set Doc = CATIA.ActiveDocument
    Dim Pt As Part: Set Pt = Doc.Part
    Dim Hss As HybridShapes: Set Hss = Pt.HybridBodies.Item(1).HybridShapes
    Call Pt.Update
    
    Debug.Print "*** エラー時の線の長さ取得テスト スタート ***"
    
    '長さを取得したい線
    Dim L3 As HybridShape: Set L3 = Hss.Item("L3")
    Dim L3Ref As Reference: Set L3Ref = Pt.CreateReferenceFromGeometry(L3)
    
    '変更する点-本当はHybridShapePointCoord
    Dim P4Vri As Variant: Set P4Vri = Hss.Item("P4")
    
    '長さ測定
    Dim L3Lng As Double
    L3Lng = Doc.GetWorkbench("SPAWorkbench").GetMeasurable(L3Ref).length
    Debug.Print "変更前(エラー無し) : " & CStr(L3Lng) & "mm"
    
    '端点位置変更 - 未更新
    Call P4Vri.SetCoordinates(Array(5, 5, 0))
    
    '更新-エラー発生
    On Error Resume Next
        '本当はエラーで止まる
        Call Pt.Update
    On Error GoTo 0
    L3Lng = Doc.GetWorkbench("SPAWorkbench").GetMeasurable(L3Ref).length
    Debug.Print "変更後(エラー)-Update : " & CStr(L3Lng) & "mm"
    
    '目的の要素のみローカル更新
    Call Pt.UpdateObject(L3)
    L3Lng = Doc.GetWorkbench("SPAWorkbench").GetMeasurable(L3Ref).length
    Debug.Print "変更後-UpdateObject_線のみ : " & CStr(L3Lng) & "mm"
    
    '目的の要素の履歴分ローカル更新
    Call Pt.UpdateObject(P4Vri)
    Call Pt.UpdateObject(L3)
    L3Lng = Doc.GetWorkbench("SPAWorkbench").GetMeasurable(L3Ref).length
    Debug.Print "変更後-UpdateObject_点・線 : " & CStr(L3Lng) & "mm"
End Sub

PartのUpdateでは、エラーが出る為 "On Error Resume Next" を利用してます。

実際に試した結果はこち

*** エラー時の線の長さ取得テスト スタート ***
変更前(エラー無し) : 10mm
変更後(エラー)-Update : 10mm
変更後-UpdateObject_線のみ : 25mm
変更後-UpdateObject_点・線 : 25mm

Update(エラーが発生した状態)では、未更新な状態な為変更される前の
長さを取得してしまいます。
[目的の要素のみローカル更新] と [目的の要素の履歴分ローカル更新](こっちは無意味)
では、単にL3のみの更新とP4・L3の更新の違いです。
実は、 [目的の要素のみローカル更新] では "上手く行かないかも" と思っていたの
ですが、依存する要素(今回はP4)も更新されました。
過去に履歴を時系列順に更新してやらないと上手く出来なかった事が
あったので、僕の場合はこのように更新するように心掛けています。


ここからが試すまで知らなかった事です。
上記のコードを最初このようにしていました。

	・・・
    '目的の要素のみローカル更新
    Call Pt.UpdateObject(L3Ref) 'オブジェクトではなくリファレンスを更新
    L3Lng = Doc.GetWorkbench("SPAWorkbench").GetMeasurable(L3Ref).length
    Debug.Print "変更後-UpdateObject_線のみ : " & CStr(L3Lng) & "mm"

実はこれで問題無いと思っていたからです。
実際に実行してみると、UpdateObject時にエラーとなってしまいました。

AutomationManualを見るとUpdateObjectメソッドの引数は
"AnyObject" で Referenceオブジェクト は "AnyObject" を継承しており
実際によく利用しています。

f:id:kandennti:20170621131307p:plain

上記の事を考えると、CATPart内でエラーが発生している場合は、リファレンスでの
UpdateObjectでは、正しく処理されないようです。
各要素のオブジェクトとリファレンスは、ほぼ同等のものと思っていたのですが・・・。

こちらも非常に勉強になりました。

アクティブCATPartを、Igesファイルにバッチ変換

ちょっと業務上欲しくなったので、CATPartファイルをIgesに変換する為の
マクロを作成しました。" マクロにする必要ある? " と思った方、正解です。

単に変換するだけであれば、必要性を感じないのですが、オプションの
こちらの部分を変更しソリッドとサーフェスで二回変換してます。
f:id:kandennti:20170620123934p:plain
オプションを表示させる際、CATIA起動後の一回目は少し間が空くんですよね。
二回目以降はストレス無く表示されるのですが。

又、変換処理時間が結構かかる場合もあるので、バッチモードを利用し
オペレーションを奪われないようにしました。

'vba sample_ExpIges_Surf_Solid_ver0.0.1  using-'ver0.0.10'
'アクティブなPartファイルをIges(Surface/Solid)でエクスポート

Option Explicit

Sub CATMain()
    'ドキュメントのチェック
    If Not KCL.CanExecute("PartDocument") Then Exit Sub
    
    'ドキュメント取得/チェック
    Dim PDoc As PartDocument: Set PDoc = CATIA.ActiveDocument
    If PDoc.Saved = False Then
        If MsgBox("変更されています。上書き保存し作業を続けますか?", vbYesNo) = vbNo Then Exit Sub
        PDoc.Save
    End If
    
    'アクティブパス
    Dim FullPath As String: FullPath = PDoc.FullName
    If FullPath = vbNullString Then
        MsgBox "新規ファイルです。一度保存を行ってから再実行してください!"
        Exit Sub
    End If
    Dim Path As Variant: Path = KCL.SplitPathName(FullPath)
    
    'エクスポート用パス
    Dim SurfPath As String
    SurfPath = KCL.GetNewName(Path(0) & "\" & Path(1) & "_Surface.igs")
    
    Dim SolidPath As String
    SolidPath = KCL.GetNewName(Path(0) & "\" & Path(1) & "_Solid.igs")
    
    'Iges設定取得 0-Surface 1-Solid
    Dim IgsMSBO As Long
    IgsMSBO = CATIA.SettingControllers.Item("CATIdeIgesSettingCtrl").ExportMSBO
    
    'catiaの実行ファイルパス取得
    Dim CatPath  As String
    CatPath = CATIA.SystemService.Environ("CATDLLPath")
    
    '環境ファイルパス取得
    Dim EnvironmentPath  As Variant
    EnvironmentPath = KCL.SplitPathName(CATIA.SystemService.Environ("CATEnvName"))
    
    '確認
    Dim Msg As String
    Msg = "[ " & Path(1) & " ]をIges(サーフェス/ソリッド)に変換します。" & vbNewLine & _
            "宜しいですか?"
    If MsgBox(Msg, vbYesNo) = vbNo Then Exit Sub
    
    'バッチ用マクロファイル作成
    Dim MacroPath  As String
    MacroPath = KCL.GetNewName(Path(0) & "\" & Path(1) & ".catvbs")
    Call KCL.WriteFile(MacroPath, CreateCatvbsSource(FullPath, SurfPath, SolidPath, MacroPath, IgsMSBO))
    
    'バッチモード起動
    Call ExecuteButchMode(CatPath & "\CNEXT.exe", EnvironmentPath(0), EnvironmentPath(1), MacroPath)
    
    MsgBox "変換処理を始めました!"
End Sub

'バッチモード起動
Private Sub ExecuteButchMode( _
                ByVal CatExePath As String, _
                ByVal EnvDirPath As String, _
                ByVal EnvPath As String, _
                ByVal MacroPath As String)
    Dim Cmd As String
    Cmd = CatExePath & " -direnv " & EnvDirPath & _
            " -env " & EnvPath & " -batch  -macro " & _
            Chr(34) & MacroPath & Chr(34)
    Call CreateObject("Wscript.Shell").Exec(Cmd)
End Sub

'CatVbsソース
Private Function CreateCatvbsSource( _
                ByVal ReadPath As String, _
                ByVal SurfPath As String, _
                ByVal SolidPath As String, _
                ByVal MacroPath As String, _
                ByVal MSBO As Long) As String
    Dim ArySurf As Variant: ArySurf = KCL.SplitPathName(SurfPath)
    Dim ArySolid As Variant: ArySolid = KCL.SplitPathName(SolidPath)
    Dim Msg As String
    Msg = "[" & ArySurf(0) & "] に" & _
        "[" & ArySurf(1) & "." & ArySurf(2) & "] と" & _
        "[" & ArySolid(1) & "." & ArySolid(2) & "] を作成しました"

    CreateCatvbsSource = _
    "Sub CATMain()" & vbNewLine & _
    "    FullPath = " & Chr(34) & ReadPath & Chr(34) & vbNewLine & _
    "    SurfPath = " & Chr(34) & SurfPath & Chr(34) & vbNewLine & _
    "    SolidPath = " & Chr(34) & SolidPath & Chr(34) & vbNewLine & _
    "    IgsMSBO = " & CStr(MSBO) & vbNewLine & _
    "    Call ExpIges(FullPath, SurfPath, SolidPath, IgsMSBO)" & vbNewLine & _
    "    Call CATIA.Quit" & vbNewLine & _
    "    Set Fso = CreateObject(" & Chr(34) & "Scripting.FileSystemObject" & Chr(34) & ")" & vbNewLine & _
    "    Call Fso.DeleteFile(" & Chr(34) & MacroPath & Chr(34) & ", True)" & vbNewLine & _
    "    Msgbox " & Chr(34) & Msg & Chr(34) & vbNewLine & _
    "End Sub" & vbNewLine & _
    "Private Sub ExpIges(ByVal ReadPath, ByVal SurfPath, ByVal SolidPath, ByVal MSBO)" & vbNewLine & _
    "    Set PDoc = CATIA.Documents.Open(CStr(ReadPath))" & vbNewLine & _
    "    Set IgsSetAtt = CATIA.SettingControllers.Item(" & Chr(34) & "CATIdeIgesSettingCtrl" & Chr(34) & ")" & vbNewLine & _
    "    IgsSetAtt.ExportMSBO = 0" & vbNewLine & _
    "    Call PDoc.ExportData(SurfPath, " & Chr(34) & "igs" & Chr(34) & ")" & vbNewLine & _
    "    IgsSetAtt.ExportMSBO = 1" & vbNewLine & _
    "    Call PDoc.ExportData(SolidPath, " & Chr(34) & "igs" & Chr(34) & ")" & vbNewLine & _
    "    IgsSetAtt.ExportMSBO = MSBO" & vbNewLine & _
    "End Sub"
End Function

・バッチモードのCATIAを起動し、アクティブなCATPartをそちらでも開く為
 保存しておく必要が有ります。
 (マクロ実行中に確認・上書き保存は可能です)

・処理後は、アクティブなCATPartファイルと同一フォルダ内に
 [アクティブなCATPartファイル] + [_Surface.igs]
 [アクティブなCATPartファイル] + [_Solid.igs]
 の二つのファイルが出来上がります。

・変換後のファイル名が重複するものになる場合は、
 ファイル名の最後に [_(数字)] が付いたファイルとなります。
 (上書きしません)

・一時的にcatvbsファイルが作成されますが、処理後は削除します。

・バッチモード起動を利用している為、小さなファイルは逆に遅いです・・・。

GUI起動の場合、CATIAは二個までの制限(同一リリースの場合)があると
思うのですが、バッチモード起動の場合はメモリの許す限り起動出来そうな
雰囲気があります。二つ起動した方が早いかも。

又、こちらの記載もバッチモード起動で解決出来るかな?
DrawをPDFでエクスポート (未解決) - C#ATIA

ThickOnTheFly1

こちらでクリックした際、肉厚を取得しました。
クリックした面に3Dな矢印と注記を作る - C#ATIA

こちらの方法を流用して
ボディの外側をマクロで判断する - C#ATIA

動的に肉厚を取得できないかなぁ? と思い挑戦中です。

画面左下のステータスバーの位置に、測定した肉厚の値を表示させています。
マウスカーソルの動きにあわせて、2つの点がボディ上を動き回っています。
この2点の距離を肉厚として表示させています。

UpdateObjectとComputeの違い

こちらで教えて頂いた、Computeメソッド
UpdateとUpdateObject - C#ATIA

こちらで試した際は気が付かなかったのですが、
スピードテスト5 - C#ATIA

PartクラスのUpdateObjectメソッドは各HybridShapeクラスのComputeメソッドを
呼び出しているだけなのかな? と思っていたのですが、
ちょっと違うようなのでご紹介。


こちらの画像のようなデータで、交差コマンドを実行します。
f:id:kandennti:20170614124931p:plain
手動であれば、もちろん失敗します。

そこで、こちらのコードを実行します。

'vba Test_Update_errer
Sub CATMain()
    '準備
    Dim Pt As Part: Set Pt = CATIA.ActiveDocument.Part
    Dim Fact As HybridShapeFactory: Set Fact = Pt.HybridShapeFactory
    Dim Hb As HybridBody: Set Hb = Pt.HybridBodies.Item(1)
    
    '二つの面のリファレンス
    Dim Ref1 As Reference: Set Ref1 = Pt.CreateReferenceFromGeometry(Hb.HybridShapes.Item(1))
    Dim Ref2 As Reference: Set Ref2 = Pt.CreateReferenceFromGeometry(Hb.HybridShapes.Item(2))
    
    '交差 未アップデート状態
    Dim Intersect As HybridShapeIntersection
    Set Intersect = Fact.AddNewIntersection(Ref1, Ref2)
    Intersect.PointType = 0
    
    '更新テスト
    Dim Msg$: Msg = ""
    
    On Error GoTo ExitUpdeteTest
        'Compute
        Msg = "Computeでエラー"
        'Hb.AppendHybridShape Intersect
        Call Intersect.Compute
        
        'UpdateObject
        Msg = "UpdateObjectでエラー"
        Call Pt.UpdateObject(Intersect)
    On Error GoTo 0
    
    Msg = "エラーなし"

ExitUpdeteTest:
    MsgBox Msg
End Sub

実行結果はこち

f:id:kandennti:20170614124905p:plain

Computeメソッドは、失敗していてもエラーを吐き出さないんです。
コメント化している部分を外し、形状セットに挿入後でも同様です。

確実に処理が成功しない場合は、ちょっと危険か香りがします。

ボディの外側をマクロで判断する

以前、3次元測定機の測定結果(CSV)をCATIAに取り込み、
実物とCADデータを差を調整しながらモデリングを行った事があったのですが、
大量の点をイチイチ測定する手間が非現実的なため、誤差を測定する為の
マクロを作成し作業をしたことが有ります。

単に 点 - ボディ 間の距離を測定するだけであれば、こちらの方法で
良いのですが、(リファレンスさえ取得できれば、何でも同じです)
ボディ - ボディ の最短距離の測定3 - C#ATIA

測定点がCADデータに比べ 小さいのか? 大きいのか?
を判断する方法が最初はわかりませんでした。

イロイロと試しているうちにわかったのですが、ボディとボディ内に
含まれている点の距離を測定した場合、
パートデザインフューチャー(パッド等)と点の距離を測定すると "0" となり
ボディの表面と点の距離を測定すれば、実際に離れている距離が
得られます。

f:id:kandennti:20170613150918p:plain

実際に、これをマクロ化することでOKでした。

'vba sample_IsInBox
'ボディ表面上は外側に判断

Option Explicit

Sub CATMain()

    '必要なもの
    Dim PDoc As PartDocument: Set PDoc = CATIA.ActiveDocument
    Dim Pt As Part: Set Pt = PDoc.Part
    Dim Fact As HybridShapeFactory: Set Fact = Pt.HybridShapeFactory
    
    '点
    Dim Pnt As HybridShapePointCoord
    Set Pnt = Pt.HybridBodies.Item(1).HybridShapes.Item(1)
    
    '点リファレンス
    Dim PntRef As Reference
    Set PntRef = Pt.CreateReferenceFromGeometry(Pnt)
    
    'パーツボディ
    Dim Bd As Body: Set Bd = Pt.MainBody
    
    'パーツボディの最後のパートデザインフューチャー
    Dim LastShape As Shape
    Set LastShape = Bd.Shapes.Item(Bd.Shapes.Count)
    
    'フューチャーのリファレンス
    Dim ShapeRef As Reference
    Set ShapeRef = Pt.CreateReferenceFromGeometry(LastShape)
    
    '抽出(サーフェス)したリファレンス
    Dim SurfRef As Reference
    Set SurfRef = CreateExtractRef(Pt, Fact, ShapeRef)
    
    '点とフューチャーの距離
    Dim ShapeLng As Double
    ShapeLng = GetMaximumLength(Pt, PntRef, ShapeRef)
    
    '点と抽出の距離
    Dim SurfLng As Double
    SurfLng = GetMaximumLength(Pt, PntRef, SurfRef)
    
    '判断
    Dim Msg As String
    Msg = Pnt.Name & "は、" & Bd.Name & "の" & _
          IIf(ShapeLng = SurfLng, "外", "内") & _
          "側にあります"
    MsgBox Msg
    
    Call Fact.DeleteObjectForDatum(SurfRef)
End Sub

'抽出
Private Function CreateExtractRef( _
                    ByVal Pt As Part, _
                    ByVal Fact As HybridShapeFactory, _
                    ByVal Ref As Reference) As Reference
    Dim HSExt As HybridShapeExtract
    Set HSExt = Fact.AddNewExtract(Ref)
    With HSExt
        .PropagationType = 3
        .ComplementaryExtract = False
        .IsFederated = False
        .Compute
    End With
    
    Set CreateExtractRef = Pt.CreateReferenceFromGeometry(HSExt)
End Function

'最短距離測定
Private Function GetMaximumLength(ByVal Pt As Part, _
                                  ByVal Ref1 As Reference, _
                                  ByVal Ref2 As Reference) As Double
    GetMaximumLength = Pt.Parent.GetWorkbench("SPAWorkbench") _
                         .GetMeasurable(Ref1) _
                         .GetMinimumDistance(Ref2)
End Function

表面のリファレンスを得る為に、"抽出" を利用しましたが、座標変換(同じ座標系)・
移動(移動量0)・回転・スケーリング・・・・何でも構わないと思います。

こんな感じで、原点を重心とした□100のボディと点が存在するデータを
想定しています。
f:id:kandennti:20170613150933p:plain

実行した感じはこちら。

これ自体は無意味ですが、判断は出来ています。


こちらのコメント部分に、チラッと書いたのですが、
UpdateとUpdateObject - C#ATIA
この方法を利用すれば、ボディに限りどちらが外側にオフセット
されるのかを判断する事が可能です。


余談ですが、3次元スキャナ等から得たデータとCADデータの差を見ることが
出来るフリーソフトはこちらで入手可能です。
GOM Inspect

スピードテスト5

一応、こちらの続きです。
http://kantoku.hatenablog.com/entry/2015/04/15/195513

前回のコメントで、"HybridShapeクラスのComputeメソッドでもアップデート出来るよ" と
imihitoさんに教えていただき、少し速くなりそうな気がしたので、
こちらのコードを元に試してみました。
http://kantoku.hatenablog.com/entry/2015/04/11/172004

元のコードが32bitだった為、テストが手軽に行えるようにしつつ
64bit用に修正しました。

'VBA Speed_Test using-'ver0.0.10'
Option Explicit

Private Const Max = 500         '点の生成数
Private Const TestCount = 5&    'テスト回数

Sub CATMain()
    Debug.Print "*** start ***"
    
    Dim i&, PDoc As PartDocument
    For i = 1 To TestCount
        Set PDoc = CATIA.Documents.Add("Part")
        
        KCL.SW_Start
        Call SubCreateDatumPoint
        Debug.Print KCL.SW_GetTime & "秒"
        
        Call PDoc.Close
    Next
End Sub

Private Sub SubCreateDatumPoint()
    Dim oPart As MECMOD.Part
    Dim oHybShpFact As HybridShapeTypeLib.HybridShapeFactory
    Dim oHybBdy As MECMOD.HybridBody
    Dim oHybShpPt 'As HybridShapeTypeLib.HybridShapePointCoord
    Dim oHybShpPtExp As HybridShapeTypeLib.HybridShapePointExplicit
    Dim i As Integer
    Dim oPt As Variant
    Dim colMyObj1 As Collection
    Dim oMyobj As Object
    
    Set oPart = CATIA.ActiveDocument.Part
    Set oHybShpFact = oPart.HybridShapeFactory

    Set colMyObj1 = New Collection

'------------ Add Body ------------------------------
    Set oHybBdy = oPart.HybridBodies.Add()

'------------ Create RefPoint ------------------------------
    oPt = Array(0, 0, 0)
    Set oHybShpPt = oHybShpFact.AddNewPointCoord(oPt(0), oPt(1), oPt(2))
    Call oHybBdy.AppendHybridShape(oHybShpPt)
    Call oPart.UpdateObject(oHybShpPt)

'------------ Create DetumPoints ------------------------------
    For i = 1 To 500
        oPt(0) = oPt(0) + 10
        Call oHybShpPt.SetCoordinates(oPt)
        Call oPart.UpdateObject(oHybShpPt)
        Set oHybShpPtExp = oHybShpFact.AddNewPointDatum(oHybShpPt)
        Call colMyObj1.Add(oHybShpPtExp)
    Next
'------------ Append DetumPoints ------------------------------
    With oHybBdy
        For Each oMyobj In colMyObj1
            Call .AppendHybridShape(oMyobj)
        Next
    End With
    Call oHybShpFact.DeleteObjectForDatum(oHybShpPt)    'Delete RefPoint
    Call oPart.Update
    
    Set colMyObj1 = Nothing
End Sub

SubCreateDatumPoint関数は前回のままで、KCLは単に時間の測定に利用している
だけです。 結果はこちら。

*** start ***
1.191秒
1.195秒
1.195秒
1.195秒
1.193秒

32bit当時は、1.6~1.7秒程だったので64bitの恩恵を受けているようです。

見直したところ、SubCreateDatumPoint関数をこんな感じに修正すると
更に時間が短縮できそうだとわかりました。

Private Sub SubCreateDatumPoint()
    Dim Pt As Part: Set Pt = CATIA.ActiveDocument.Part
    Dim Fact As HybridShapeFactory: Set Fact = Pt.HybridShapeFactory

'------------ Add Body ------------------------------
    Dim HBdy As HybridBody: Set HBdy = Pt.HybridBodies.Add()

'------------ Create RefPoint ------------------------------
    Dim Pos As Variant: Pos = Array(0#, 0#, 0#)
    Dim Pnt As Variant: Set Pnt = Fact.AddNewPointCoord(Pos(0), Pos(1), Pos(2))

'------------ Create DetumPoints ------------------------------
    Dim Ary() As HybridShapePointExplicit: ReDim Ary(Max) As HybridShapePointExplicit
    Dim i As Long
    
    For i = 1 To Max
        Pos(0) = Pos(0) + 10#
        Call Pnt.SetCoordinates(Pos)
        Call Pt.UpdateObject(Pnt)
        Set Ary(i) = Fact.AddNewPointDatum(Pnt)
    Next
    
'------------ Append DetumPoints ------------------------------
    For i = 1 To Max
        Call HBdy.AppendHybridShape(Ary(i))
    Next
    Call Fact.DeleteObjectForDatum(Pnt)
    Call Pt.UpdateObject(HBdy)
End Sub

変数名等も修正してしまいましたが、主に
・最初のRefPoint作成時、更新しない
・コレクション → 配列化
・Partファイルのアップデート → 形状セットのアップデート
です。 結果はこち

*** start ***
1.02秒
1.021秒
1.015秒
1.01秒
1.014秒

"キー付きコレクション" も試しましたが、配列の方が少しだけ速い気がしました。
0.1秒強の短縮ですが、一番効果を感じたのは、
"Partファイルのアップデート → 形状セットのアップデート"
でした。


ここで本題の "Computeメソッド" です。利用出来そうなのが
RefPointの座標値書き換え後のアップデート時のみです。

 ・・・
'------------ Create DetumPoints ------------------------------
    Dim Ary() As HybridShapePointExplicit: ReDim Ary(Max) As HybridShapePointExplicit
    Dim i As Long
    
    For i = 1 To Max
        Pos(0) = Pos(0) + 10#
        Call Pnt.SetCoordinates(Pos)
        Call Pnt.Compute 'ここだけ書き換え
        Set Ary(i) = Fact.AddNewPointDatum(Pnt)
    Next
 ・・・

結果はこちら。

*** start ***
1.017秒
1.024秒
1.018秒
1.019秒
1.016秒

処理量が少ないので、誤差レベルの違いしか感じません・・・。


個人的には点・線・面等を作成する関数化させるのですが、
アップデートしたい為だけに、Partクラスを引数渡しする場合が
多々あります。 それが不要になるのは、かなりうれしい。

UpdateとUpdateObject

"マクロで作成した面の色を変更したけど、上手く反映されない"
と言った内容の御質問を頂きました。

このような状態のデータで、オフセット面を作成する操作の
マクロを記録しました。

f:id:kandennti:20170612170332p:plain

'vba
Sub CATMain()
    Dim partDocument1 As PartDocument
    Set partDocument1 = CATIA.ActiveDocument
    
    Dim part1 As Part
    Set part1 = partDocument1.Part
    
    Dim parameters1 As Parameters
    Set parameters1 = part1.Parameters
    
    Dim hybridShapeSurfaceExplicit1 As HybridShapeSurfaceExplicit
    Set hybridShapeSurfaceExplicit1 = parameters1.Item("サーフェス.1")
    
    Dim reference1 As Reference
    Set reference1 = part1.CreateReferenceFromObject(hybridShapeSurfaceExplicit1)
    
    Dim hybridShapeFactory1 As HybridShapeFactory
    Set hybridShapeFactory1 = part1.HybridShapeFactory
    
    Dim hybridShapeOffset1 As HybridShapeOffset
    Set hybridShapeOffset1 = hybridShapeFactory1.AddNewOffset(reference1, 5#, True, 0.01)
    
    Dim hybridBodies1 As HybridBodies
    Set hybridBodies1 = part1.HybridBodies
    
    Dim hybridBody1 As HybridBody
    Set hybridBody1 = hybridBodies1.Item("形状セット.1")
    
    hybridBody1.AppendHybridShape hybridShapeOffset1
    
    part1.InWorkObject = hybridShapeOffset1
    
    part1.Update
End Sub

色を変更する為の(手抜き感たっぷりな)関数をこんな感じで作成しました。

'色設定
Private Sub SetColor(ByVal Surf As HybridShapeOffset)
    With CATIA.ActiveDocument.Selection
        .Clear
        .Add Surf
        .VisProperties.SetRealColor 0, 255, 0, 1
        .Clear
    End With
End Sub

引数に渡されたオフセットなオブジェクトを緑色に変更するだけです。

問題は、このSetColor関数をCatMainの何処に記載するか? です。


一番問題ないのが、一番最後の位置です。

	・・・
    hybridBody1.AppendHybridShape hybridShapeOffset1
    
    part1.InWorkObject = hybridShapeOffset1
    
    part1.Update
    
    Call SetColor(hybridShapeOffset1) '追加
End Sub

御質問頂いた方の場合は、こんな感じのコードでした。

	・・・
    hybridBody1.AppendHybridShape hybridShapeOffset1
    
    part1.InWorkObject = hybridShapeOffset1
    
    Call SetColor(hybridShapeOffset1) '追加
    
    part1.Update
End Sub

ご本人も "Updateの後に色の変更であれば可能" と言う認識は
されておりました。

そこでちょっと意地悪く、こんなコードにしてみます。

	・・・
    'hybridBody1.AppendHybridShape hybridShapeOffset1 'コメント化
    
    part1.InWorkObject = hybridShapeOffset1
    
    part1.Update
    
    Call SetColor(hybridShapeOffset1) '追加
    
    hybridBody1.AppendHybridShape hybridShapeOffset1 '追加
    
    part1.Update

アップデート後に色は変えるものの、形状セットに入れる(AppendHybridShape)
のは、後回しにします。 この場合、色は変更されませんでした。

この事から、
・色の変更は、アップデート後に行う。
・アップデートする前に、形状セットに入れておく必要がある。

と言うことになりそうです。


そこで、このようなコードを提案してみました。

	・・・
    Dim hybridShapeOffset1 As HybridShapeOffset
    Set hybridShapeOffset1 = hybridShapeFactory1.AddNewOffset(reference1, 5#, True, 0.01)
    
    Call part1.UpdateObject(hybridShapeOffset1) '追加
    Call SetColor(hybridShapeOffset1) '追加
    
    Dim hybridBodies1 As HybridBodies
    Set hybridBodies1 = part1.HybridBodies
	・・・

オフセット面を作成(AddNewOffset)し、形状セットに入れる前に
UpdateObjectメソッドでアップデートし、色を変更する手順です。

UpdateObjectメソッドであれば、Updateメソッドと異なり、
形状セットに入れておく必要がありません。 

実はこの方法を利用すると、一時的に必要な要素を形状セットに入れる
必要が無くなる為、処理が非常に速くなります。
(場合によっては遅くなります)