「2Dの曲線を選択した際、近い側の端点を取得したい」との相談を
頂きました。
通常要素の選択であれば、Selection.SelectElement2が殆どなのですが、
今回の場合は、Selection.IndicateOrSelectElement2Dを使用します。
理由は単純で、クリックした位置の座標を取得する為です。
クリックした位置さえ取得出来れば、後は2つの端点との距離を比較し
短い方が近い端点と判断出来ます。
'vba 2Dの線を選択した際、近い側の端点を取得 Option Explicit Sub CATMain() Dim doc As DrawingDocument Set doc = CATIA.ActiveDocument Dim vi As DrawingView Set vi = doc.Sheets.ActiveSheet.views.ActiveView Do '選択後は配列が返ってきて 'crv_near(0)-選択した線 'crv_near(1)-近い側の端点(Point2D) Dim crv_near As Variant crv_near = GetNearPoint() If IsEmpty(crv_near) Then Exit Do End If Call initCircle(crv_near(1)) Loop vi.Activate MsgBox "Done" End Sub '*** 2D線を選択 - 選択した曲線と近い側の端点取得 *** 'return array(Curve2D,Point2D) Private Function GetNearPoint() As Variant Dim doc As DrawingDocument Set doc = CATIA.ActiveDocument Dim sel As Variant ' Selection Set sel = doc.selection sel.Clear '座標選択 Dim status As String Dim ObjectSelected Dim WindowLocation(1) Dim filter As Variant filter = Array("Curve2D") 'WindowLocationの座標値はアクティブビューに対しての座標値 status = "MouseMove" Dim pos As Variant Do While (status = "MouseMove") status = sel.IndicateOrSelectElement2D( _ "線を選択/キャンセル ESC", _ filter, _ False, _ False, _ True, _ ObjectSelected, _ WindowLocation) If Not ObjectSelected Then pos = WindowLocation End If Loop 'ESCキー If sel.Count2 < 1 Then Exit Function End If '選択した線 Dim crv As Curve2D Set crv = sel.Item(1).Value '*** クリック位置の座標 *** 'アクティブビュー Dim ac As DrawingView Set ac = doc.Sheets.ActiveSheet.views.ActiveView 'ターゲットビュー Dim tg As DrawingView Set tg = crv.Parent.Parent 'ビュー間ベクトル Dim tran_vec As Variant tran_vec = GetTransVec(ac, tg) '該当するビューの座標に変換 pos = Add2d(tran_vec, pos) '*** クリック位置と端点比較 *** 'crvのVariant Dim crvVri As Variant Set crvVri = crv '始点座標値 Dim pos1(1) As Variant Call crvVri.StartPoint.GetCoordinates(pos1) '終点座標値 Dim pos2(1) As Variant Call crvVri.EndPoint.GetCoordinates(pos2) '距離比較 Dim res As Variant If LengSqr(pos, pos1) > LengSqr(pos, pos2) Then res = Array(crv, crv.EndPoint) Else res = Array(crv, crv.StartPoint) End If GetNearPoint = res End Function 'ビュー間ベクトル Private Function GetTransVec( _ ByVal act_v As DrawingView, _ ByVal tgt_v As DrawingView) As Variant GetTransVec = Sub2d( _ Array(act_v.xAxisData, act_v.yAxisData), _ Array(tgt_v.xAxisData, tgt_v.yAxisData)) End Function '和2D Private Function Add2d( _ ByVal V1 As Variant, _ ByVal V2 As Variant) As Variant Add2d = Array(V1(0) + V2(0), V1(1) + V2(1)) End Function '差2D Private Function Sub2d( _ ByVal V1 As Variant, _ ByVal V2 As Variant) As Variant Sub2d = Array(V1(0) - V2(0), V1(1) - V2(1)) End Function '2点距離の平方数 Private Function LengSqr( _ ByVal p1 As Variant, _ ByVal p2 As Variant) As Double Dim A#: A = p2(0) - p1(0) Dim B#: B = p2(1) - p1(1) LengSqr = A * A + B * B End Function '*************** '確認用 点を中心に円を描く Private Sub initCircle( _ ByVal pnt As Point2D) Dim vi As DrawingView Set vi = pnt.Parent.Parent vi.Activate 'アクティブにする必要有り Dim fact As Factory2D Set fact = vi.Factory2D Dim pntVri As Variant Set pntVri = pnt Dim pos(1) Call pntVri.GetCoordinates(pos) Dim crl As Circle2D Set crl = fact.CreateClosedCircle(pos(0), pos(1), 5#) crl.CenterPoint = pnt End Sub
LengSqr関数(今見るとイマイチな名称です…)ですが、配列を点座標と
想定し2点間距離の平方数を返します。
この方法は、C# OpenGLプラットフォーム「ヒスイ」で学びました。
コンピューターは人に比べれば計算は高速ですが、全て同一速度で
処理されるわけではないのも事実です。平方根の演算も時間のかかる
(コストの高い)処理らしいです。
2点間の正しい距離を演算するためには、平方根の演算が必要となり
ますが(平方根を避けた近似演算式があるようですが、知りません)
今回のように「どちらの点が近いのかな?」と言う処理に関して言えば
平方根を演算しなくても、誤った結果にはならないです。
(結果が逆転する事は無い)
とは言え、「この程度の処理にそこまで気にする必要あるの?」とも
受け取れるのですが・・・。
余談ですが、「ヒスイ」の公開が無くなっていたんですね。
株式会社カタッチ
開発された方は、既に退社されているので仕方ないのは確かですが。