こちらの続きです。
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プロパティを
作ってみましたが、使うかな・・・。
こちらで内外積に自信がないと記載しましたが、内積については
ある程度、Fusion360のAPIで確認しました。(ありがたい)
配列でベクトル演算 - 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
後はバウンダリボックスの亜種か・・・。