C#ATIA

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

ObjectCollectionオブジェクト

先週作っていたスプリクト、行き詰まり感からちょっと放置。
こちらに面白そうなテーマがあったので、取り組んでみました。
How to remove inner sketch lines from an intersection sketch? - Autodesk Community

空のスケッチを選択したらエラーとか、移動しているコンポーネントだと
違う位置に出来上がる(未テスト)とか、駄目な部分は多々あるのですが
動くのでUpしたのですが、前から気になっていた事が
少しわかったので覚書です。

Fusion360APIには、ObjectCollectionオブジェクトと言うのがあるんです。
Help

オブジェクトを格納するものなのですが、Pythonの場合はリスト・セット・タプルがあり、
大したメソッドも無いので態々使う利用も無いかな? と思っていました。

今まで、面やボディを作るようなスプリクトを作った事が無かったのですが
今回はパッチサーフェスを作ってます。この辺です。
Help

returnValue = patchFeatures_var.createInput(boundaryCurve, operation)

このパラメータの "boundaryCurve" に幾つかのタイプのオブジェクトを渡すことが
出来るようなのですが、今回はプロファイルが複数入ったObjectCollection
オブジェクトを渡しています。
手動で操作した時、パッチコマンドでは1回のコマンドで複数のプロファイルを
指定出来ます。要は手動もスプリクトも同じような仕様なんですね。

但し、ここがリスト等じゃダメなんです。ObjectCollectionオブジェクトの
存在理由がやっとわかりました。
…リストとかの方が、遥かに便利なんですけどね。

flatten関数

こちらでチョロッと書いたのですが、覚書です。
Re: Need help with macro to check through NC programs - Autodesk Community
肝になるのは、複数あるNCプログラム内で登録されているツールパスを全て
取得する方法です。

以前、書きましたがPMillのマクロでは、ネストしたList(List内にList)を作る事が
出来ません。(イロイロ試したつもりですが、やっぱり作れません)
複数のツールパスが入っているNCプログラムの場合、ツールパスのリストを取得するには
こんな感じです。(NCプログラム名が 'hoge' の場合)

	object list nc_tps_obj = entity('ncprogram', 'hoge').nctoolpath

nctoolpathメソッド? は、Helpにも記載されていない気がしてます。

デバッガで見るとこんな状態です。
f:id:kandennti:20180611104321p:plain
MAP型は、object型で(大体)取得できます。
でも、これは1つのNCプログラム分なので全てのプログラムのツールパスを取得したい場合
[entity] List([object] List)の状態のネストしたListの形になるため、
直接変数で受け取ることが出来ません。

そこでflatten関数の登場です。
他の言語同様、flatten関数はネストしたListを1次のList化するものです。
その為、全てのNCプログラムの全てのツールパス名を取得する為には

	string list nc_tps = extract(flatten(extract(folder('ncprogram'), 'nctoolpath')), 'name')

の1行で出来ます。
extractがネストしてたりするので、わかりにくいのですけどね。

import neu_dev; neu_dev.list_functions()

Fusion360にテキストコマンドがあるのを知りませんでした。
Fusion 360:テキスト コマンド - Technology Perspective from Japan
でも、何か役に立つかな…。
どちらかと言うと、実際に操作したログを吐き出して見れると
ありがたいのですが、今のところそれらしきファイルも見当たりません。
(サーバーとのやり取りのログファイルは何処かにありました)

今回のタイトルは、”ヘルプを参照するには~” の後に記載されているコマンドです。
薄すぎて見えなかったので。

マウスカーソルの座標値を取得する6

こちらの続きです。
マウスカーソルの座標値を取得する5 - C#ATIA

取り組んでいる時間が無さそうなので、現状のものを公開しておきます。
そこそこ機能するはずです。

#FusionAPI_python
#Author-kantoku
#Description-MouseMoveTest ver0.0.3

import adsk.core, adsk.fusion, traceback
import math

_ui  = None
_handlers = []
_faces = []
_covunit = 0
_defLenUnit = ''
_draftVec = None

#選択面変更
class MyCommandInputChangedHandler(adsk.core.InputChangedEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            eventArgs = adsk.core.InputChangedEventArgs.cast(args)
    
            if eventArgs.input.id != 'DraftVec':
                return
                
            selectionInput = adsk.core.SelectionCommandInput.cast(eventArgs.input)
            print(selectionInput.selectionCount)
            
            global _draftVec
            if selectionInput.selectionCount == 0 :
                app = adsk.core.Application.get()
                des = adsk.fusion.Design.cast(app.activeProduct)
                comp = des.rootComponent
                vecZ = comp.zConstructionAxis.geometry.direction
                _draftVec = vecZ
                return
            
            ent = selectionInput.selection(0).entity
            vec = None
            if ent.classType() == 'adsk::fusion::SketchLine':
                vec = ent.worldGeometry.asInfiniteLine().direction
            _draftVec = vec
            
        except:
            global _ui
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

#このコマンドのイベント・ダイアログ作成
class MyCommandCreatedHandler(adsk.core.CommandCreatedEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            global _handlers
            cmd = adsk.core.Command.cast(args.command)
            
            #破棄
            onDestroy = MyCommandDestroyHandler()
            cmd.destroy.add(onDestroy)
            _handlers.append(onDestroy)
            
            #勾配向き
            onInputChanged = MyCommandInputChangedHandler()
            cmd.inputChanged.add(onInputChanged)
            _handlers.append(onInputChanged)
            
            #マウス
            onMouseMove = MyMouseMoveHandler()
            cmd.mouseMove.add(onMouseMove)
            _handlers.append(onMouseMove)
            
            inputs = cmd.commandInputs
            
            inputs.addTextBoxCommandInput('Pos', 'マウス3D座標値 :', 'Non!', 1, True)
            inputs.addTextBoxCommandInput('MinR', '最小R :', '-', 1, True)
            inputs.addTextBoxCommandInput('Ang', '角度 :', '-', 1, True)
            
            selInput = inputs.addSelectionInput('DraftVec', '角度基準', 'DraftVec')
            selInput.setSelectionLimits(0,1)

            selInput.selectionfilters = ['SketchLines']
            
        except:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
            
#このコマンドの破棄
class MyCommandDestroyHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            adsk.terminate()
        except:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

#MouseMoveイベント
class MyMouseMoveHandler(adsk.core.MouseEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        eventArgs = adsk.core.MouseEventArgs.cast(args)
        cmd = eventArgs.firingEvent.sender
        inputs = cmd.commandInputs
        
        #ビューポイント
        vp = eventArgs.viewport

        pos_ui = inputs.itemById('Pos')
        minr_ui = inputs.itemById('MinR')
        ang_ui = inputs.itemById('Ang')

        #マウス3D座標値
        onface = OnFace(vp, eventArgs.viewportPosition)
        if onface == None:
            pos_ui.text = 'Non!'
            minr_ui.text = '-'
            ang_ui.text = '-'
            return
        else:
            pos_ui.text = 'x:{:.3f} y:{:.3f} z:{:.3f}'.format(
                onface[1].x * _covunit,
                onface[1].y * _covunit,
                onface[1].z * _covunit)
                
        #法線
        ang_ui.text = '{:.3f} deg'.format(math.degrees(GetNomal(onface[0], onface[1])))
        
        #曲率
        cture = GetCurvature(onface[0], onface[1])
        if cture == None:
            minr_ui.text = '-'
        else:
            if round(cture,4) != 0 :
                crv_info = '{:.3f}{}'.format(
                        1 / cture * _covunit * -1, 
                        _defLenUnit)
                minr_ui.text = crv_info
            else:
                minr_ui.text = '-'

#法線
def GetNomal(face, pnt):
    eva = face.evaluator
    res, pram = eva.getParameterAtPoint(pnt)
    returnValue, normal = eva.getNormalAtPoint(pnt)
    ang = _draftVec.angleTo(normal)
    
    if ang > math.pi * 0.5 :
        ang = (math.pi * -1) + ang
    return ang
    
#曲率
def GetCurvature(face, pnt):
    if face.geometry.classType() == 'adsk::core::Plane':
        return None
    
    eva = face.evaluator
    res, pram = eva.getParameterAtPoint(pnt)
    returnValue, maxTangent, maxCurvature, minCurvature = eva.getCurvature(pram)
    
    if returnValue:
        return maxCurvature
    return None

#マウスカーソルの3D取得
def OnFace(vp, vp_pos):
    d3pos = vp.viewToModelSpace(vp_pos)
    cam = vp.camera
    vec = cam.eye.vectorTo(cam.target)
    
    pnt = adsk.core.Point3D.create(
        d3pos.x + vec.x, 
        d3pos.y + vec.y, 
        d3pos.z + vec.z)
        
    mouse3d = adsk.core.Line3D.create(d3pos, pnt).asInfiniteLine()    
    
    ints = [(face, mouse3d.intersectWithSurface(geo))
            for (face, geo) in _faces if mouse3d.intersectWithSurface(geo).count > 0]
    
    ints = [(face, p) 
            for (face, pnts) in ints
            for p in pnts]

    ints = [(face, p, face.evaluator.getParameterAtPoint(p))
            for (face, p) in ints]
    
    ints = [(face, p, prm)
            for (face, p, (res, prm)) in ints if res]
    
    ints = [(face, p, prm)
            for (face, p, prm) in ints]
            
    ints = [(face, p, cam.eye.distanceTo(p))
            for (face, p, prm) in ints if face.evaluator.isParameterOnFace(prm)]
    
    if len(ints) < 1:
        return None
    
    return min(ints, key = (lambda x: x[2]))
    
def run(context):
    try:
        global _ui
        app = adsk.core.Application.get()
        _ui = app.userInterface
                
        cmdDef = _ui.commandDefinitions.itemById('Mouse_Move_Test')
        if not cmdDef:
            cmdDef = _ui.commandDefinitions.addButtonDefinition(
                'Mouse_Move_Test', 
                'Mouse_Move_Test', 
                'Mouse_Move_Test')

        onCommandCreated = MyCommandCreatedHandler()
        cmdDef.commandCreated.add(onCommandCreated)
        _handlers.append(onCommandCreated)
        
        des = adsk.fusion.Design.cast(app.activeProduct)
        
        #全サーフェス取得
        global _faces
        _faces = [(face, face.geometry)
            for comp in des.allComponents if comp.isBodiesFolderLightBulbOn
            for bBody in comp.bRepBodies if bBody.isLightBulbOn & bBody.isVisible
            for face in bBody.faces]

        #単位準備
        global _covunit, _defLenUnit
        unitsMgr = des.unitsManager
        _defLenUnit = unitsMgr.defaultLengthUnits
        _covunit = unitsMgr.convert(1, unitsMgr.internalUnits, _defLenUnit)
        
        #角度基準
        global _draftVec
        comp = des.rootComponent
        _draftVec = comp.zConstructionAxis.geometry.direction

        cmdDef.execute()

        adsk.autoTerminate(False)
    except:
        if _ui:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

スプリクト実行した際、こんなダイアログが出現します。
f:id:kandennti:20180608122844p:plain
マウス3D座標値:マウスカーソル位置の3D座標です。面の上になっていない場合は表示されません。
 又、未テストですがコンポーネントを移動・回転させている場合は、正しい位置を表示しません。
最小R:凸をプラス 凹をマイナスでRサイズを表示します。
角度:"角度基準" 未指定の場合、ルートコンポーネントのZ軸を元に角度を表示します。
 水平を0° 垂直を90° とし、アンダーカット部分ではマイナスで表示します。
角度基準:"角度" を表示させる際の基準となる向きを指定できます。
 現状はスケッチの直線のみです。(ここが現在のお悩み)

マウスカーソルの座標値を取得する5

こちらの続きです。
マウスカーソルの座標値を取得する4 - C#ATIA

前回上手くいかなかった原因が、単にチェックすべきベクトルを間違えていた
と言う、お粗末な内容でした・・・。(Fusion360は正しいです)

現状、ルートコンポーネントのZ軸に対しての角度は望んだ状態で
取得できる様になっているのですが、皆が全てZ軸で調べたいとは思えないので
任意の方向で測定できるようにしたいです。

その為、方向を選択できるように SelectionCommandInput を設置します。
おなじみの矢印のこれです。
f:id:kandennti:20180606191010p:plain
これ、便利なのですがイベントで悩みました。

選択された状態(又は全く選択されていない状態)をイベントで掴みたいのですが
InputChangedEventで行うべきなのか? SelectionEventで行うべきなのか?
が良くわかりませんでした。
わからないと悩んでいても仕方ないので、両方を試したのですが
要らないイベントばかり発生し、肝心なものにたどり着かない状況になり
途方に暮れていたのですが、こちらに答えが記載されていました。
Solved: how to use the SelectionEventHandler - Autodesk Community
InputChangedEventArgsで拾って、inputを SelectionCommandInput に
キャストするんですね。(僕も一ヶ月後これを見ても、何書いているのか理解できない)

もう2個ぐらい機能付ければ、公開したいな。
小原さんがアイデアに記載した、これを解決したい。
検査ー勾配解析、曲率マップ解析等でマウスを乗せたところに詳細な値を表示してほしい。 - Autodesk Community

マウスカーソルの座標値を取得する4

こちらの続きです。
マウスカーソルの座標値を取得する3 - C#ATIA
3D空間でマウスの位置が取得できるようになったので、マウスの位置で
曲率と勾配角度を動的に取得したいです。そう、CATIAのオンザフライの機能を
実現したいと細々とやってます。
テストモデルはこのような感じで、勾配解析を行った状態です。
f:id:kandennti:20180606104408p:plain
勾配角度はZ軸(青い線)方向とします。紫色は垂直面で、青緑?色が水平面です。
最小R(曲率の逆数)は無事に取得できているようなのですが、
勾配が上手く取得出来ていません。

    app = adsk.core.Application.get()
    des = adsk.fusion.Design.cast(app.activeProduct)
    comp = des.rootComponent
    
    #pnt - サーフェス上の任意の点
    #maxTangent - サーフェス上の任意の点の法線3Dベクトル
    axisZ = comp.zConstructionAxis.geometry
    tang = adsk.core.InfiniteLine3D.create(pnt, maxTangent)
    measMng = app.measureManager
    ang = measMng.measureAngle(axisZ, tang).value

比較的最近実装されたmeasureManagerオブジェクトを利用し、
2つの無限直線の角度を求めています。
結果はこちら
f:id:kandennti:20180606104420p:plain
左が水平面で右が垂直面です。 両方90°です…。
R面を測定していても水平に近い部分で90°弱になり、
垂直に近い部分で0°強になる為、個人的な直感とは逆です。
又、アンダーカットとなる部分ではマイナスの値で返ってきて
欲しいのですが、全てプラスです。(atan関数なんだろうなぁ)

よく見たらVecter3Dオブジェクトに2つのベクトル間の角度を求める
メソッドがあった為、コードを修正。

    ・・・
    vecZ = comp.zConstructionAxis.geometry.direction
    ang = vecZ.angleTo(maxTangent)

こちらの方が、はるかにコードが短かったです。
でも結果は同じです。

真面目に計算しなきゃなら無そうなので、悩み中です。

ThickOnTheFly2

こちらの続き? です。
ThickOnTheFly1 - C#ATIA
こちら作りかけて止めました。続けてもいないのですがコードを
記載していなかったので・・・・。
正直な所、変数・関数名等が酷いのですが、直す気力がありません。

'vba using-'KCL0.0.12'
'動的にボディの厚みをStatusBarに表示させる
'厚み解析のアルゴリズム自体が正しくないです

Private Const MaxLng = 2000000#
Private Const MinLng = 0.002

Sub CATMain()
    Dim Sel 'As Selection
    Set Sel = CATIA.ActiveDocument.Selection
    Dim Pt As Part
    Set Pt = CATIA.ActiveDocument.Part
    Dim PlaneXY As AnyObject
    Set PlaneXY = Pt.OriginElements.PlaneXY
    Dim fact As HybridShapeFactory
    Set fact = Pt.HybridShapeFactory
    
    Dim Status 'As Long
    Dim WindowLocation2D(1)
    Dim WindowLocation3D(2)
    Dim ObjectSelected
    
    Dim Hb As HybridBody
    Set Hb = Pt.hybridBodies.Add
    
    'パーツボディ
    Dim Bd As Body
    
    Set Bd = KCL.SelectItem("body", "Body")
    
    'パーツボディの最後のパートデザインフューチャー
    Dim LastShape As Shape
    Set LastShape = Bd.Shapes.Item(Bd.Shapes.Count)
    
    'フューチャーのリファレンス
    Dim RefShape As Reference
    Set RefShape = Pt.CreateReferenceFromGeometry(LastShape)
    
    Dim ShapeSrf As HybridShape: Set ShapeSrf = CreateExtract(Pt, fact, RefShape)
    Dim RefShapeSrf As Reference: Set RefShapeSrf = Pt.CreateReferenceFromGeometry(ShapeSrf)
    
    'カーソルがボディ上?
    Dim OnBdyLst As Collection: Set OnBdyLst = New Collection
    
    '原点
    Dim ori As HybridShape: Set ori = CreatePnt(Pt, fact, Array(0#, 0#, 0#))
    Call Pt.UpdateObject(ori)
    Dim RefOri As Reference: Set RefOri = Pt.CreateReferenceFromGeometry(ori)
    
    Dim PntCam As HybridShape: Set PntCam = CreatePnt(Pt, fact, Array(0#, 0#, 0#))
    Dim RefCam As Reference: Set RefCam = Pt.CreateReferenceFromGeometry(PntCam)
    
    'マウスカーソル3D位置
    Dim PntTgt As HybridShape: Set PntTgt = CreatePnt(Pt, fact, Array(0#, 0#, 1#))
    Dim RefTgt As Reference: Set RefTgt = Pt.CreateReferenceFromGeometry(PntTgt)
    
    'カメラ方向単位ベクトル
    Dim CamUnitVec As HybridShape: Set CamUnitVec = CreatePnt(Pt, fact, Array(0#, 0#, 1#))
    Dim RefCamUnitVec As Reference: Set RefCamUnitVec = Pt.CreateReferenceFromGeometry(CamUnitVec)
    
    'カメラ方向用単位線
    Dim UnitLin As HybridShape: Set UnitLin = CreateLine(Pt, fact, RefOri, RefCamUnitVec, 0#, 0#)
    Dim RefUnitLin As Reference: Set RefUnitLin = Pt.CreateReferenceFromGeometry(UnitLin)
    Call OnBdyLst.Add(UnitLin)
    
    'カメラ方向
    Dim CamVec As HybridShape: Set CamVec = CreateDirection(fact, RefUnitLin)
    Dim RefCamVec As Reference: Set RefCamVec = Pt.CreateReferenceFromGeometry(CamVec)
    Call OnBdyLst.Add(CamVec)
    
    Dim LinVew As HybridShape: Set LinVew = CreateExtrude(fact, RefTgt, CamVec, MaxLng, MaxLng)
    Dim RefVew As Reference: Set RefVew = Pt.CreateReferenceFromGeometry(LinVew)
    Call OnBdyLst.Add(LinVew)
    
    Dim Isc As HybridShape: Set Isc = GetIntersect(fact, RefShapeSrf, RefVew)
    Dim RefIsc As Reference: Set RefIsc = Pt.CreateReferenceFromGeometry(Isc)
    Call OnBdyLst.Add(Isc)
    
    Dim Near As HybridShape: Set Near = GetNear(fact, RefIsc, RefCam)
    Dim RefNer As Reference: Set RefNer = Pt.CreateReferenceFromGeometry(Near)
    Call OnBdyLst.Add(Near)
    Hb.AppendHybridShape Near: Call SetColor(Near)
    
    Dim Rev As Boolean: Rev = True 'これいらないかも
    Dim Nml As HybridShape: Set Nml = CreateNormal(fact, RefShapeSrf, RefNer, MinLng, MaxLng, Rev)
    Dim RefNml As Reference: Set RefNml = Pt.CreateReferenceFromGeometry(Nml)
    Call OnBdyLst.Add(Nml)
    
    'Nml.Pointエラー対策
    Dim NmlPnt As HybridShapePointOnCurve: Set NmlPnt = CreatePntOnCrv(fact, RefNml, 0#, Rev) '***********
    Dim RefNmlPnt As Reference: Set RefNmlPnt = Pt.CreateReferenceFromGeometry(NmlPnt)
    Call OnBdyLst.Add(NmlPnt)
    
    '厚さリスト
    Dim ThickLst As Collection: Set ThickLst = New Collection
    
    Dim ThkIsc As HybridShape: Set ThkIsc = GetIntersect(fact, RefShapeSrf, RefNml)
    Dim RefThkIsc As Reference: Set RefThkIsc = Pt.CreateReferenceFromGeometry(ThkIsc)
    Call ThickLst.Add(ThkIsc)
    
    Dim ThkPnt As HybridShape: Set ThkPnt = GetNear(fact, RefThkIsc, RefNer)
    Dim RefThkPnt As Reference: Set RefThkPnt = Pt.CreateReferenceFromGeometry(ThkPnt)
    Call ThickLst.Add(ThkPnt)
    Hb.AppendHybridShape ThkPnt: Call SetColor(ThkPnt)
    
    Dim vp As Variant ' Viewpoint3D
    Set vp = GetViewPnt3D
    Dim origin(2) As Variant:
    Dim sight(2) As Variant
    Dim Thi$: Thi = "0"
    
    Do
        Status = Sel.IndicateOrSelectElement3D(PlaneXY, "t=" & Thi, Array("HybridShapePointCoord"), True, True, True, ObjectSelected, WindowLocation2D, WindowLocation3D)

        Select Case Status
            Case "Cancel"
                Exit Do
            Case "Normal"
            
            Case "MouseMove"
                Call vp.GetOrigin(origin)
                Call UpdatePnt(Pt, PntCam, origin)
                Call UpdatePnt(Pt, PntTgt, WindowLocation3D)
                Call vp.GetSightDirection(sight)
                Call UpdatePnt(Pt, CamUnitVec, sight)
                If TryUpdate(Pt, OnBdyLst) Then
                    Debug.Print GetMinLng(Pt, RefShape, RefNmlPnt)
                    If Not GetMinLng(Pt, RefShape, RefNmlPnt) = 0 Then
                        'Rev
                        Nml.Orientation = IIf(Nml.Orientation = 1, -1, 1)
                        Call Pt.UpdateObject(Nml)
                        NmlPnt.Orientation = Nml.Orientation
                        Call Pt.UpdateObject(NmlPnt)
                    End If
                    If TryUpdate(Pt, ThickLst) Then
                        Thi = CStr(GetMinLng(Pt, RefNer, RefThkPnt))
                    End If
                End If
        End Select
    Loop
End Sub

Private Sub SetColor(ByVal Shp As AnyObject)
    With CATIA.ActiveDocument.Selection
        .Clear
        .Add Shp
        .VisProperties.SetRealColor 0, 255, 0, 1
        .VisProperties.SetSymbolType 4
        .Clear
    End With
End Sub

Private Function CreateExtrude( _
                    ByVal fact As HybridShapeFactory, _
                    ByVal Ref As Reference, _
                    ByVal Dir As HybridShapeDirection, _
                    ByVal StLng As Double, _
                    ByVal EdLng As Double) As HybridShape
    Set CreateExtrude = fact.AddNewExtrude(Ref, StLng, EdLng, Dir)
End Function

Private Function CreateDirection( _
                    ByVal fact As HybridShapeFactory, _
                    ByVal Ref As Reference) As HybridShape
    Set CreateDirection = fact.AddNewDirection(Ref)
End Function

Private Function TryUpdate( _
                    ByVal Pt As Part, _
                    ByRef LstObj As Collection) As Boolean
    TryUpdate = False
    Dim Shp As HybridShape
    On Error Resume Next
        For Each Shp In LstObj
            Call Pt.UpdateObject(Shp)
            If Not Err.Number = 0 Then
                Err.Number = 0
                Exit Function
            End If
        Next
    On Error GoTo 0
    TryUpdate = True
End Function

'点-線上
Private Function CreatePntOnCrv( _
                    ByVal fact As HybridShapeFactory, _
                    ByVal CrvRef As Reference, _
                    ByVal Lng As Double, _
                    ByVal Rev As Boolean) As Reference
    Dim Pnt As HybridShapePointOnCurve
    Set Pnt = fact.AddNewPointOnCurveFromDistance(CrvRef, Lng, Rev)
    
    Set CreatePntOnCrv = Pnt
End Function

'法線
Private Function CreateNormal( _
                    ByVal fact As HybridShapeFactory, _
                    ByVal SurfRef As Reference, _
                    ByVal pntRef As Reference, _
                    ByVal SLng As Double, _
                    ByVal ELng As Double, _
                    ByVal Rev As Boolean) As Reference
    Dim Lin As HybridShapeLineNormal
    Set Lin = fact.AddNewLineNormal(SurfRef, pntRef, SLng, ELng, Rev)
    Set CreateNormal = Lin
End Function

'抽出
Private Function CreateExtract( _
                    ByVal Pt As Part, _
                    ByVal fact As HybridShapeFactory, _
                    ByVal Ref As Reference) As HybridShape
    Dim HSExt As HybridShapeExtract
    Set HSExt = fact.AddNewExtract(Ref)
    With HSExt
        .PropagationType = 3
        .ComplementaryExtract = False
        .IsFederated = False
    End With
    Call Pt.UpdateObject(HSExt)
    Set CreateExtract = HSExt
End Function

'近傍
Private Function GetNear( _
                    ByVal fact As HybridShapeFactory, _
                    ByVal InterRef As Reference, _
                    ByVal pntRef As Reference) ' As Reference
    Dim Near As HybridShapeNear
    Set Near = fact.AddNewNear(InterRef, pntRef)

    Set GetNear = Near
End Function

'交差
Private Function GetIntersect( _
                    ByVal fact As HybridShapeFactory, _
                    ByVal ShpRef As Reference, _
                    ByVal LinRef As Reference) ' As Reference
    Set GetIntersectRef = Nothing
    
    Dim Inter As HybridShapeIntersection
    Set Inter = fact.AddNewIntersection(ShpRef, LinRef)
    Inter.PointType = 0
    
    Set GetIntersect = Inter
End Function

'最短距離測定
Private Function GetMinLng( _
                    ByVal Pt As Part, _
                    ByVal Ref1 As Reference, _
                    ByVal Ref2 As Reference) As Double
    GetMinLng = MaxLng '-1
    On Error Resume Next
        GetMinLng = Pt.Parent.GetWorkbench("SPAWorkbench") _
                         .GetMeasurable(Ref1) _
                         .GetMinimumDistance(Ref2)
    On Error GoTo 0
End Function

Private Sub UpdatePnt( _
                    ByVal Pt As Part, _
                    ByRef Pnt As Variant, _
                    ByVal Pos As Variant)
    Call Pnt.SetCoordinates(Pos)
    Call Pt.UpdateObject(Pnt)
End Sub

'点
Private Function CreatePnt( _
                    ByVal Pt As Part, _
                    ByVal fact As HybridShapeFactory, _
                    ByVal Ary As Variant) As HybridShape
    Dim Pnt As HybridShapePointCoord
    Set Pnt = fact.AddNewPointCoord(Ary(0), Ary(1), Ary(2))
    Call Pt.UpdateObject(Pnt)
    Set CreatePnt = Pnt
End Function

Private Function CreateLine( _
                    ByVal Pt As Part, _
                    ByVal fact As HybridShapeFactory, _
                    ByVal Ref1 As Reference, _
                    ByVal Ref2 As Reference, _
                    ByVal StLng As Double, _
                    ByVal EdLng As Double) As HybridShape
    Dim Lin As HybridShapeLinePtPt
    Set Lin = fact.AddNewLinePtPtExtended(Ref1, Ref2, StLng, EdLng)
    Call Pt.UpdateObject(Lin)
    Set CreateLine = Lin
End Function

'表示のUpdate
Private Sub UpdateScene(ByVal Scene As Variant)
    Dim Viewer As Viewer3D: Set Viewer = CATIA.ActiveWindow.activeviewer
    Dim VPnt3D As Variant 'Viewpoint3D
    Set VPnt3D = Viewer.Viewpoint3D
    
    Dim Ary As Variant
    Ary = KCL.GetRangeAry(Scene, 0, 2)
    Call VPnt3D.PutOrigin(Ary)
    
    Ary = KCL.GetRangeAry(Scene, 3, 5)
    Call VPnt3D.PutSightDirection(Ary)
    
    Ary = KCL.GetRangeAry(Scene, 6, 8)
    Call VPnt3D.PutUpDirection(Ary)
    
    VPnt3D.FieldOfView = Scene(9)
    VPnt3D.FocusDistance = Scene(10)
    
    Call Viewer.Update
End Sub

'Viewpoint3Dからシーン取得
Private Function GetScene3D(ViewPnt3D As Viewpoint3D) As Variant
    Dim vp As Variant: Set vp = ViewPnt3D
    
    Dim origin(2) As Variant: Call vp.GetOrigin(origin)
    
    Dim sight(2) As Variant: Call vp.GetSightDirection(sight)
    GetScene3D = KCL.JoinAry(origin, sight)
    
    Dim up(2) As Variant: Call vp.GetUpDirection(up)
    GetScene3D = KCL.JoinAry(GetScene3D, up)
    
    Dim FieldOfView(0) As Variant: FieldOfView(0) = vp.FieldOfView
    GetScene3D = KCL.JoinAry(GetScene3D, FieldOfView)
    
    Dim FocusDist(0) As Variant: FocusDist(0) = vp.FocusDistance
    GetScene3D = KCL.JoinAry(GetScene3D, FocusDist)
End Function

'現状の視点取得
Private Function GetViewPnt3D() As Viewpoint3D
    Set GetViewPnt3D = CATIA.ActiveWindow.activeviewer.Viewpoint3D
End Function

確か、一度XY平面を通過する位置にマウスを移動しないと、厚みが表示されなかった
記憶です。(奥行きの値を取得する為です)

最初に必要となるGSDの要素をHybridShapeFactoryで作り出し、
マウスを動かす度にUpdateしまくり、厚みを表示させています。
そのため、チラツキ感が酷いです。

「厚みを表示」と書いておりますが、算出方法が(少なくとも)2種類あり
こちらのサイトの "RAY法" になるのだと思います。
GeomCaliper | ジオムキャリパー | CATIA V5モデルの肉厚の測定と表示 | アイコクアルファ株式会社
本当は "Sphere法" を行いたいのですが、アルゴリズムが良くわからないんです。
(測定対象となる相手の面さえ見つければ良いのですが、効率良く見つけ出す方法が
 わかりません)


・・・先日知ったのですが、海外の方もここを見て頂いているようでして、
3年ぐらい続けるとそんな事もあるんですね。