Vectors 3

This is my third try at vectors. It starts with basic vector algebra.

A vector is an ordered triple of numbers, representing the xyz coordinates of the head, the tail at 0,0,0. A vector and a point have the same structure, an array of 3 doubles. Vector algebra functions accept a vector as input and return the calculated vector. Position comes into play when we want to display the vector in autocad. (these are NOT all debugged on first draft)

Here are the elementary vector functions.
Plus (U,V) returns vector U + V
Minus (U,V) returns vector U – V
Scalar(c, U) returns vector c * U
Dot(U, V) returns double dot product
Leng(U) returns double length of vector
UnitV(U) returns unit vector along U
Dist(U, V) returns double distance between vectors
Angle(U, V) returns angle between vectors as double in radians
Ortho(U, V) returns boolean True if vectors are perpendicular
Proj(U, V) returns vector V projected on U
Neg(U) returns negative vector

Draw(vec) Draws vector in autocad as simple line

the function to create a point takes the triples input and returns the array of 3 doubles.

dim pt1() as double
pt1 = PT(1,2,3)

this is used as the basic vector creation function.

dim u() as double
u= VEC(1,2,3)

Function vec(x As Double, y As Double, z As Double) As Double()
    Dim pnt(0 To 2) As Double
    pnt(0) = x: pnt(1) = y: pnt(2) = z
    vec = pnt
End Function
Function plus(u() As Double, v() As Double) As Double()
    Dim w(0 To 2) As Double
    w(0) = u(0) + v(0)
    w(1) = u(1) + v(1)
    w(2) = u(2) + v(2)
    
    plus = w
End Function

Function scalar(c As Double, u() As Double) As Double()
    Dim w(0 To 2) As Double
    w(0) = c * u(0)
    w(1) = c * u(1)
    w(2) = c * u(2)
    
    scalar = w
End Function

Function minus(u() As Double, v() As Double) As Double()
    Dim w(0 To 2) As Double
    w(0) = u(0) - v(0)
    w(1) = u(1) - v(1)
    w(2) = u(2) - v(2)
    
    minus = w
End Function

Function dot(u() As Double, v() As Double) As Double
    Dim w As Double
    w = u(0) * v(0) + u(1) * v(1) + u(2) * v(2)
    dot = w
End Function

Function leng(u() As Double) As Double
    Dim w As Double
    w = u(0) ^ 2 + u(1) ^ 2 + u(2) ^ 2
    w = Sqr(w)
        
    leng = w
End Function

Function unitv(u() As Double) As Double()
    Dim w() As Double
    Dim L As Double
    
    L = leng(u)
    w = scalar(1 / L, u)

    unitv = w
End Function

Function dist(u() As Double, v() As Double) As Double
    Dim L As Double
    L = leng(minus(u, v))
    
    dist = L
End Function

Function angle(u() As Double, v() As Double) As Double
    Dim Dot_UV As Double
    Dim len_U As Double
    Dim len_V As Double
    Dim cos_theta As Double
 
    Dot_UV = dot(u, v)
    len_U = leng(u)
    len_V = leng(v)
    
    cos_theta = Dot_UV / (len_U * len_V)
    
    angle = WorksheetFunction.Acos(cos_theta)
End Function

Function ortho(u() As Double, v() As Double) As Boolean
    Dim w As Double
    w = dot(u, v)
    
    If w = 0 Then
    ortho = True
    Else
    ortho = False
    End If
End Function

Function proj(u() As Double, v() As Double) As Double()
    Dim w() As Double
    Dim x As Double
    Dim Dot_UV As Double
    Dim Dot_UU As Double
        
    x = Dot_UV / Dot_UU
    w = scalar(x, u)
    
    proj = w
End Function

Function neg(u() As Double) As Double()
    Dim w(0 To 2) As Double
    w(0) = -1 * u(0)
    w(1) = -1 * u(1)
    w(2) = -1 * u(2)
    
    neg = w
End Function

To draw a vector in autocad, this is borrowed from the line wrapper, I kept the optional layer parameter even though i dont intend to use it much at first.

g_pt is a public point variable, same as a vector, if we set it each time, its easy to draw vectors end to end.
we could save the newly created line object the same way, and sometimes thats useful, but i removed it for now.


Public u() As Double
Public v() As Double
Public g_pt() As Double

Sub draw(vec() As Double, startpt() As Double, Optional strlayer As Variant)
    Dim lineobj As acadline
    Dim endpt() As Double
        
    endpt = pt(vec(0) + startpt(0), vec(1) + startpt(1), vec(2) + startpt(2))
    Set lineobj = acadDoc.ModelSpace.AddLine(startpt, endpt)
        
    If Not IsMissing(strlayer) Then
       lineobj.Layer = strlayer
    End If
         
    g_pt = endpt
 
  End Sub

Vectors in the Plane


Dim A() As Double, B() As Double
Dim C() As Double, D() As Double
Dim R() As Double

A = pt(4, 1, 0)
B = pt(2, -3, 0)
C = pt(-2, 2, 0)
D = pt(-3, -2, 0)

vec_draw1 A, "A"
vec_draw1 B, "B"
vec_draw1 C, "C"
vec_draw1 D, "D"

R = v_add(A, B)
vec_draw1 R, "A+B"

R = v_add(A, C)
vec_draw1 R, "A+C"

R = v_add(A, D)
vec_draw1 R, "A+D"

R = v_add3(A, B, C)
vec_draw1 R, "A+B+C"

R = vec_add_2(1, A, 2, B)
vec_draw1 R, "A+2B"

R = vec_add_2(1, A, -3, C)
vec_draw1 R, "A-3C"

R = v_add3(A, C, v_m(1 / 3, D))
vec_draw1 R, "A+C+1/3D"


Sub vec_draw1(pt1() As Double, Optional str_text As Variant)
'line from origin to pt1
Dim lineobj As AcadLine
Set lineobj = acadDoc.ModelSpace.AddLine(pt(0, 0, 0), pt1)

    If Not IsMissing(str_text) Then
         txt1 CStr(str_text), pt1, 0.25
    End If
End Sub

'add 2 vectors, return vector
Function v_add(pt1() As Double, pt2() As Double) As Double()
v_add = pt(pt1(0) + pt2(0), pt1(1) + pt2(1), pt1(2) + pt2(2))
End Function

'multiply scalar by vector, return vector
Function v_m(m As Double, pt1() As Double) As Double()
v_m = pt(m * pt1(0), m * pt1(1), m * pt1(2))
End Function

'add 3 vectors, return vector
Function v_add3(pt1() As Double, pt2() As Double, pt3() As Double) As Double()
v_add3 = pt(pt1(0) + pt2(0) + pt3(0), pt1(1) + pt2(1) + pt3(1), pt1(2) + pt2(2) + pt3(2))
End Function

'add 2 vectors each multiplied by a scalar, A-B would be vec_add_2(1, A, -1, B)
Function vec_add_2(m As Double, pt1() As Double, n As Double, pt2() As Double) As Double()
Dim temp1() As Double,  temp2() As Double
temp1 = v_m(m, pt1)
temp2 = v_m(n, pt2)

vec_add_2 = v_add(temp1, temp2)
End Function

it would be possible to do this on one line but it would be hard to read.

Dim temp1() As Double, temp2() As Double

temp1 = vec_add_2(2, A, -3, B)
temp2 = vec_add_2(-3, C, 4, D)
R = v_add(temp1, temp2)
vec_draw1 R, "2A-3B-3C+4D"

Length and Direction –

Function vec_len(pt1() As Double) As Double
Dim x As Double, y As Double, z As Double
x = pt1(0): y = pt1(1): z = pt1(2)
vec_len = (x ^ 2 + y ^ 2 + z ^ 2) ^ (1 / 2)
End Function

Dividing a vector by the length (multiplying by the inverse of the length) produces a vector with length one in the same direction –

The angle of a 2D vector is a directed line measured from the positive X axis. It takes a value between 0 and 360 degrees not including 360 or 0 and 2 pi not including 2 pi. The inverse tangent is used with y/x as argument. Tangent returns an angle for an undirected line between -90 to +90 or -pi/2 to +pi/2. The code is a bit tedious but its pretty straightforward. We have to trap out zero values of x, to avoid divide by zero, then check for zeros of y and interpret, then retrieve the value for the inverse tangent and interpret according to which quadrant the head of the vector is in.

Function vec_ang(pt1() As Double) As Double
'returns angle in radians
'check for zero length vector return 0 for angle
Dim x As Double, y As Double

x = pt1(0)
y = pt1(1)

If x = 0 And y = 0 Then
    vec_ang = 0
    Exit Function
End If

'get axis directions
If x = 0 Or y = 0 Then
    If y = 0 And x > 0 Then vec_ang = 0
    If x = 0 And y > 0 Then vec_ang = Pi / 2
    If y = 0 And x < 0 Then vec_ang = Pi
    If x = 0 And y < 0 Then vec_ang = 3 * Pi / 2
Exit Function
End If

'calculate m tangent
Dim m As Double
m = y / x

If x > 0 And y > 0 Then  'First Q
'Debug.Print rad2deg(Atn(m))
vec_ang = Atn(m)
End If

If x < 0 And y > 0 Then  'Second Q
'Debug.Print rad2deg(Atn(m))
vec_ang = Pi + Atn(m)
End If

If x < 0 And y < 0 Then  'Third Q
'Debug.Print rad2deg(Atn(m))
vec_ang = Pi + Atn(m)
End If

If x > 0 And y < 0 Then  'Fourth Q
'Debug.Print rad2deg(Atn(m))
vec_ang = 2 * Pi + Atn(m)
End If

End Function


Sub vec_draw3(startpt1() As Double, vectorpt2() As Double, Optional str_text As Variant)
'line from startpoint at vector distance and angle
Dim lineobj As AcadLine
Dim pt3() As Double
pt3 = v_add(startpt1, vectorpt2)
Set lineobj = acadDoc.ModelSpace.AddLine(startpt1, pt3)

If Not IsMissing(str_text) Then
         txt1 CStr(str_text), pt1, 0.25
    End If
End Sub

triangles with random vertexes and medians – (I moved them after the program drew them)


Sub vec_draw2(pt1() As Double, pt2() As Double, Optional str_text As Variant)
'simple line from pt1 to pt2
Dim lineobj As AcadLine
Set lineobj = acadDoc.ModelSpace.AddLine(pt1, pt2)

If Not IsMissing(str_text) Then
         txt1 CStr(str_text), midpt2(pt1, pt2), 0.25
    End If
End Sub