C#ATIA

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

2次元のベクトルオブジェクト

こちらの続きです。
2次元の点オブジェクト - C#ATIA

引き続きベクトルオブジェクトです。
機能的にかなり不足していますが、とりあえず使いたい用途では
これで十分な気がします。クラスモジュールです。

'vba Vec2D.cls

Option Explicit

Private x_ As Double
Private y_ As Double
Private length_ As Double
Private zero_ As Boolean

Private Sub Class_Initialize()
    x_ = 0
    y_ = 0
    length_ = 0
    zero_ = True
End Sub


Private Sub Class_Terminate()
    
End Sub


'**プロパティ**
Public Property Get x() As Double
    x = x_
End Property


Public Property Let x(ByVal value As Double)
    x_ = value
End Property


Public Property Get y() As Double
    y = y_
End Property


Public Property Let y(ByVal value As Double)
    y_ = value
End Property


Public Property Get length() As Double
    length = length_
End Property


Public Property Get is_zero() As Boolean
    is_zero = zero_
End Property


'**メソッド-非破壊**

'クローン
Public Function clone() As Vec2D
    Dim vec As Vec2D
    Set vec = New Vec2D
    
    vec.with_array Array(x_, y_)
    
    Set clone = vec
End Function


'ポイント化
Public Function as_point() As Pnt2D
    Dim pnt As Pnt2D
    Set pnt = New Pnt2D
    
    pnt.with_array Array(x_, y_)
    
    Set as_point = pnt
End Function


'配列化
Public Function as_array() As Variant
    as_array = Array(x_, y_)
End Function


''外積
'Public Function cross(ByVal vector As Vec2D) As Double
'    cross = x_ * vector.x - y_ * vector.y
'End Function


'内積
Public Function dot(ByVal vector As Vec2D) As Double
    dot = x_ * vector.x + y_ * vector.y
End Function


'文字
Public Function str() As String
    str = x_ & "," & y_
End Function


'**メソッド-破壊**

'長さ設定-内部
Private Sub set_length()
    Dim length As Double
    length = Sqr(x_ * x_ + y_ * y_)
    
    If length <= 0 Then
        zero_ = True
    Else
        zero_ = False
    End If

    length_ = length
End Sub


'差
Public Sub subtract(ByVal vector As Vec2D)
    x_ = x_ - vector.x
    y_ = y_ - vector.y
    set_length
End Sub


'和
Public Sub add(ByVal vector As Vec2D)
    x_ = x_ + vector.x
    y_ = y_ + vector.y
    set_length
End Sub


'スカラー倍
Public Sub scale_by(ByVal ratio As Double)
    x_ = x_ * ratio
    y_ = y_ * ratio
    set_length
End Sub


'単位化
Public Sub normalize()
    x_ = x_ / length_
    y_ = y_ / length_
    set_length
End Sub


'配列で設定
Public Sub with_array(ByVal ary As Variant)
    If Not is_vector2d(ary) Then
        Err.Raise Number:=600, Description:="配列が不正です"
    End If

    x_ = ary(0)
    y_ = ary(1)
    set_length
End Sub


'Pnt2Dとして扱える配列か?
Private Function is_vector2d( _
    ary As Variant) _
    As Boolean

    Select Case True
        Case Not IsArray(ary)
            is_vector2d = False
        Case UBound(ary) <> 1
            is_vector2d = False
        Case Not IsNumeric(ary(0))
            is_vector2d = False
        Case Not IsNumeric(ary(1))
            is_vector2d = False
        Case Else
            is_vector2d = True
    End Select

End Function

念の為、ゼロベクトルはエラーとせず、確認用のis_zeroプロパティを
作ってみましたが、使うかな・・・。

こちらで内外積に自信がないと記載しましたが、内積については
ある程度、Fusion360APIで確認しました。(ありがたい)
配列でベクトル演算 - C#ATIA
不安だったのは、単位ベクトルにするのかどうかが分からなかった
のですが、単位ベクトル化はしないようです。
(その結果が欲しい場合は、事前にするって事ですね)

又、こちらで "使い道が思い付かない" と記載しましたが、
配列でベクトル演算 - C#ATIA
Fusion360APIのvector2Dには、外積が定義されていませんでした。
Fusion 360 Help
いつもvector3Dしか使わないので、気が付きませんでした・・・。
確かに使い道が思い付かないです。


これが標準モジュールで作ったユニットテストです。

'vba

Option Explicit

Sub unit_test_Vec2D()
    
    Dim v1 As Vec2D
    Set v1 = New Vec2D

    'with_array
    v1.with_array Array(1, 2)
    Debug.Assert "1,2" = v1.str()

    'as_array
    Debug.Assert is_equal_array(v1.as_array(), Array(1, 2))

    'clone
    Dim v2 As Vec2D
    Set v2 = v1.clone()
    Debug.Assert v2.str() = v1.str()

    'prop x,y
    v2.x = 1
    v2.y = 4
    Debug.Assert is_equal_array(v2.as_array(), Array(1, 4))

    'as_point
    Dim p As Pnt2D
    Set p = v1.as_point()
    Debug.Assert is_equal_array(p.as_array(), v1.as_array())

    'add
    v1.add v2
    Debug.Assert v1.str() = "2,6"

    'subtract
    v1.subtract v2
    Debug.Assert v1.str() = "1,2"

    'scale_by
    v1.scale_by 2
    Debug.Assert v1.str() = "2,4"

    'normalize, length
    v1.normalize
    Debug.Assert v1.length = 1

    'dot
    v1.with_array Array(3, 1)
    v2.with_array Array(1, 1.5)
    Debug.Assert v1.dot(v2) = 4.5

    v1.with_array Array(0, 1)
    v2.with_array Array(1, 7)
    Debug.Assert v1.dot(v2) = 7
    
    'zero
    v1.with_array Array(0, 0)
    Debug.Assert v1.is_zero

    MsgBox "Done"

End Sub


'配列が一致しているか?
Private Function is_equal_array( _
    ByVal ary1 As Variant, _
    ByVal ary2 As Variant) _
    As Boolean

    is_equal_array = True
    
    Select Case False
        Case IsArray(ary1)
            is_equal_array = False
            Exit Function
        Case IsArray(ary2)
            is_equal_array = False
            Exit Function
        Case UBound(ary1) = UBound(ary2)
            is_equal_array = False
            Exit Function
    End Select

    Dim i As Long
    For i = 0 To UBound(ary1)
        If ary1(i) <> ary2(i) Then
            is_equal_array = False
            Exit Function
        End If
    Next

End Function

後はバウンダリボックスの亜種か・・・。