Direction Cosines

Inclination – angle in radians or degrees a 2D line makes with the positive x-axis, measuring counter-clockwise. A line extends indefinitely in both directions.

In radians, 0 <= theta < pi
In degrees, 0 <= theta < 180

Slope – tangent of the inclination, y/x, rise over run.

Slope m = Tan alpha = y/x

Lines are perpendicular if their slopes are m1 = -1/m2

Tan alpha = – tan (180 – alpha)

A 3D line, a 3D vector, is determined by any two points. If one of these points is the origin, the coordinates of every point on the line form a set of direction numbers. Every line has an infinite set of direction numbers. The numbers always have the same proportions. You can get the coordinates of any point by multiplying the coordinates of some other point by some constant.

The direction angles of a 3D line are defined to be the angle the line makes directly with each of the positive axes. Knowing any two the third can be calculated. The angles are limited to 0 to 180, similar to the 2D inclination, but not limited to being counter-clockwise.

For an undirected line that extends indefinitely in both directions, there are two sets of direction angles,
theta and (180 – theta)

The basic calculation of 3D line direction is the division of the direction numbers by the length between the two points that generated that set. This gives the direction cosines, the x,y and z values for a line of length one. Multiplying the direction cosines by a constant gives a point on the same line at distance of the constant. The 3 direction angles of the line can be found with the Cos(-1) function.

For instance a line from the origin to (3,4,5) has a length of 7.07. The direction cosines are 3/7.07, 4/7.07, 5/7.07), the angle of the line to each of the axes, xyz, by calculator cos(-1), is approx 65, 55, and 45 degrees. Lets check that out with autocad and VBA.


Sub test24()
Call Connect_Acad

Dim x As Double, y As Double, z As Double
Dim pt0() As Double
pt0 = pt(0, 0, 0)

Dim ptX() As Double 'pt on x axis to make alpha ucs
Dim ptY() As Double 'pt on y axis to make beta ucs
Dim ptZ() As Double 'pt on z axis to make gamma ucs

'i could re-use these to only have one
Dim ptx2() As Double 'pt to define new x axis for alpha
Dim pty2() As Double 'pt to define new x axis for beta
Dim ptz2() As Double 'pt to define new x axis for gamma

Dim A() As Double, B() As Double, C() As Double
Dim dir_cos() As Double
Dim dir_ang() As Double

x = -3: y = -4: z = 5
A = pt(x, y, z)

'draw the autocad line
vec_draw1 A

ptX = pt(x, 0, 0)
ptx2 = pt(x + 1, 0, 0)
ucs ptX, ptx2, A, "ucs_alpha"
ptX = pt(Abs(x), 0, 0)
dim_ang pt0, ptX, A, midpt2(ptX, A)
label_pt A, "A"

ptY = pt(0, y, 0)
pty2 = pt(0, y + 1, 0)
ucs ptY, pty2, A, "ucs_beta"
ptY = pt(0, Abs(y), 0)
dim_ang pt0, ptY, A, midpt2(ptY, A)

ptZ = pt(0, 0, z)
ptz2 = pt(0, 0, z + 1)
ucs ptZ, ptz2, A, "ucs_gamma"
ptZ = pt(0, 0, Abs(z))
dim_ang pt0, ptZ, A, midpt2(ptZ, A)

'the box is a visual aid not always required
'Dim pt1() As Double
'pt1 = pt(x / 2, y / 2, z / 2)
'solidbox pt1, Abs(x), Abs(y), Abs(z)

'here are the calculations
dir_cos = dir_cos1(A)
Debug.Print "< " & x; ", " & y & ", " & z & " >"
Debug.Print "alpha_cos " & dir_cos(0)
Debug.Print "beta_cos " & dir_cos(1)
Debug.Print "gamma_cos " & dir_cos(2)
Debug.Print

'direction cosines are the xyz values where the line
'has a length of one
'put an autocad point object at those coordinates
draw_pt dir_cos, "L=1"

dir_ang = dir_ang1(A)
Debug.Print "Alpha " & rad2deg(dir_ang(0))
Debug.Print "Beta " & rad2deg(dir_ang(1))
Debug.Print "Gamma " & rad2deg(dir_ang(2))
Debug.Print

're-set ucs to world
set_wcs

acadApp.Update
End Sub

Call the autocad dimangular method. First the ucs is changed for each of the 3 angles. UCS requires 3 points. a new origin, a point on the new x-axis, and a point on the new y-axis. the origin is variously either (x,0,0), (0,y,0), or (0,0,z), the point on the new x-axis is variously (x+1,0,0), (0,y+1,0) or (0,0,z+1). the point on the new y-axis is always the point of the vector. that establishes a right triangle in the plane of the vector and the axis to which the angular dimension is drawn.


Sub dim_ang(pt1() As Double, pt2() As Double, pt3() As Double, pt4() As Double)
 Dim dimObj As AcadDimAngular
 'Set dimObj = acadDoc.ModelSpace.AddDimAngular(AngleVertex, firstendpoint, secondendpoint, textpoint)
 Set dimObj = acadDoc.ModelSpace.AddDimAngular(pt1, pt2, pt3, pt4)
End Sub

Independently of the autocad dimangular method, the direction cosines and direction angles are calculated. Since these are always triples, the most convenient way to store them is in a 3 place array of doubles, exactly as point coordinates are stored. In fact the direction cosines are the point coordinates for any line at the point where the length of the line is one. Both direction cosines and direction angles are calculated for a vector with tail at the origin. The version to calculate with tail not at the origin would simply do the subtraction of coordinates then call this version.

Function dir_cos1(pt1() As Double) As Double()
Dim cos_alpha As Double, cos_beta As Double, cos_gamma As Double
Dim x As Double, y As Double, z As Double
Dim D As Double

D = dist1(pt1)

If D = 0 Then
dir_cos1 = pt(0, 0, 0)
Exit Function
End If

x = pt1(0): y = pt1(1): z = pt1(2)

cos_alpha = x / D
cos_beta = y / D
cos_gamma = z / D

dir_cos1 = pt(cos_alpha, cos_beta, cos_gamma)
End Function

Function dir_ang1(pt1() As Double) As Double()
Dim alpha As Double, beta As Double, gamma As Double
Dim dir_cos() As Double
Dim pt2(0 To 2) As Double

dir_cos = dir_cos1(pt1)

alpha = WorksheetFunction.Acos(dir_cos(0))
beta = WorksheetFunction.Acos(dir_cos(1))
gamma = WorksheetFunction.Acos(dir_cos(2))

pt2(0) = alpha
pt2(1) = beta
pt2(2) = gamma

dir_ang1 = pt2

End Function

testing the subroutine for values in all 8 quadrants. the angles are always measured to the positive side of the axis. therefore they are always between 0 and 180, never negative. Getting the confidence that all quadrants return true values, the next step is to develop a sub-routine that returns the angle between two lines.

Advertisements

3D Line – part 2

The distance formula

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

Function dist2(pt1() As Double, pt2() As Double) As Double
Dim x As Double, y As Double, z As Double
x = pt2(0) - pt1(0)
y = pt2(1) - pt1(1)
z = pt2(2) - pt1(2)
dist2 = (x ^ 2 + y ^ 2 + z ^ 2) ^ (1 / 2)
End Function

test sub

Sub test17()
 Call Connect_Acad
Dim A() As Double, B() As Double
Dim x As Double, y As Double, z As Double

x = 5
y = 4
z = 3

A = pt(x, y, z)
B = pt(x, y, 0)

line1 A
txt1 midpt1(A), dec2(dist1(A))

line1 B
txt1 midpt1(B), dec2(dist1(B))

line1 pt(x, 0, 0)
txt1 midpt1(pt(x, 0, 0)), dec2(x)

line1 pt(0, y, 0)
line1 pt(0, 0, z)

line2 A, B
txt1 midpt2(A, B), dec2(dist2(A, B))

line2 pt(x, 0, 0), B
txt1 midpt2(pt(x, 0, 0), B), dec2(y)

label_pt2 A, "A", 2
label_pt2 B, "B", 2

Dim pt1() As Double
pt1 = pt(x / 2, y / 2, z / 2)
solidbox pt1, x, y, z

End Sub

text and label subs

Sub txt1(pt1() As Double, str As String, Optional height As Variant, Optional rotation As Variant)
  Dim objtxt As AcadText
  
  If IsMissing(height) Then
      height = textheight  'global var
    End If
    
  If IsMissing(rotation) Then
      rotation = 0
    End If
 
  Set objtxt = acadDoc.ModelSpace.AddText(str, pt1, height)
  objtxt.Layer = "0"
  
  If rotation <> 0 Then
  objtxt.rotation = deg2rad(CDbl(rotation))
  End If
     
 End Sub
 
Sub label_pt2(pt1() As Double, Optional str_label As String = "none", Optional prec As Integer = 4)

If IsMissing(height) Then
      height = textheight  'global var
    End If
    
Dim str As String
Dim x As Double, y As Double, z As Double
x = Round(pt1(0), prec)
y = Round(pt1(1), prec)
z = Round(pt1(2), prec)

str = "<" & x & "," & y & "," & z & ">"

If str_label <> "none" Then
str = str_label & " " & str
End If

txt1 pt1, str, textheight
End Sub
 
 Function dec2(number As Double) As Double
   Dim dbl As Double
   dbl = Round(number, 2)
   dec2 = dbl
 End Function

Acad3DSolid box sub. Transparency is a percentage 1 to 90. Higher numbers are more transparent.

Sub solidbox(pt() As Double, leng As Double, wid As Double, height As Double)

Dim objbox As Acad3DSolid
Set objbox = acadDoc.ModelSpace.AddBox(pt, leng, wid, height)
objbox.EntityTransparency = 80

acadApp.Update

End Sub

midpoint

Function midpt1(pt1() As Double) As Double()
Dim x As Double, y As Double, z As Double
x = pt1(0): y = pt1(1): z = pt1(2)
midpt1 = pt(x / 2, y / 2, z / 2)
End Function

Function midpt2(pt1() As Double, pt2() As Double) As Double()
Dim x1 As Double, y1 As Double, z1 As Double
x = (pt1(0) + pt2(0)) / 2
y = (pt1(1) + pt2(1)) / 2
z = (pt1(2) + pt2(2)) / 2
midpt2 = pt(x, y, z)
End Function

test sub


Sub test18()
Call Connect_Acad
Dim A() As Double, B() As Double, C() As Double

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

line2 A, B
line2 B, C
line2 C, A

line2 midpt2(A, B), midpt2(B, C)
line2 midpt2(B, C), midpt2(C, A)
line2 midpt2(C, A), midpt2(A, B)

label_pt2 A, "A"
label_pt2 B, "B"
label_pt2 C, "C"

label_pt2 midpt2(A, B)
label_pt2 midpt2(B, C)
label_pt2 midpt2(C, A)

acadApp.Update
End Sub

the angles to 3 decimal places

the triangles are all congruent. the middle triangle has half the perimeter of the outer triangle and one fourth the area.

3D Line – part 1

A straight line is completely determined by the coordinates of its endpoints. A straight line having a definite length and direction but no definite location in space is a vector. In its most basic form its a single point. A vector and a point are both a 3-array of doubles. Make them a dynamic array.

The functions to calculate direction, midpt, cosines, addition and scalar multiplication of vectors all return an array of 3 doubles. The line subroutines work with arrays of 3 doubles. Where I have one point argument, assuming 0,0,0 for the other, I number the routine_1. Where I have two point arguments, I number the routine_2. Passing and assigning points cleans up the code to almost logo like clarity.

dim pt1() as double, pt2() as double
pt1 = pt(2, 4, 6)
pt2 = pt(1, 9, 10)
line1 pt1
line1 pt2
line2 pt1, pt2
line2 midpt1(pt1), midpt1(pt2)

Function pt(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
pt = pnt
End Function

Sub line1(pt1() As Double)
'line from origin to pt1
Dim lineobj As AcadLine
Set lineobj = acadDoc.ModelSpace.AddLine(pt(0, 0, 0), pt1)
End Sub

Sub line2(pt1() As Double, pt2() As Double)
'line from pt1 to pt2
Dim lineobj As AcadLine
Set lineobj = acadDoc.ModelSpace.AddLine(pt1, pt2)
End Sub

Sub line3(startpt1() As Double, vectorpt2() As Double)
'line from startpoint at vector distance and angle
Dim lineobj As AcadLine
Dim pt3() As Double
pt3 = add_vectors(startpt1, vectorpt2)
Set lineobj = acadDoc.ModelSpace.AddLine(startpt1, pt3)
End Sub
Function dist1(pt1() As Double) As Double
Dim x As Double, y As Double, z As Double
x = pt1(0): y = pt1(1): z = pt1(2)
dist1 = (x ^ 2 + y ^ 2 + z ^ 2) ^ (1 / 2)
End Function

Function dist2(pt1() As Double, pt2() As Double) As Double
Dim x As Double, y As Double, z As Double
x = pt2(0) - pt1(0)
y = pt2(1) - pt1(1)
z = pt2(2) - pt1(2)
dist2 = (x ^ 2 + y ^ 2 + z ^ 2) ^ (1 / 2)
End Function

Function midpt1(pt1() As Double) As Double()
Dim x As Double, y As Double, z As Double
x = pt1(0): y = pt1(1): z = pt1(2)
midpt1 = pt(x / 2, y / 2, z / 2)
End Function

Function midpt2(pt1() As Double, pt2() As Double) As Double()
Dim x1 As Double, y1 As Double, z1 As Double
x = (pt1(0) + pt2(0)) / 2
y = (pt1(1) + pt2(1)) / 2
z = (pt1(2) + pt2(2)) / 2
midpt2 = pt(x, y, z)
End Function


Function dir_cosines1(pt1() As Double) As Double()
Dim cos_alpha As Double, cos_beta As Double, cos_gamma As Double
Dim d As Double

d = dist1(pt1)

If d = 0 Then
dir_cosines1 = pt(0, 0, 0)
Exit Function
End If

cos_alpha = pt1(0) / d
cos_beta = pt1(1) / d
cos_gamma = pt1(2) / d

dir_cosines1 = pt(cos_alpha, cos_beta, cos_gamma)
End Function


Function dir_cosines2(pt1() As Double, pt2() As Double) As Double()
Dim cos_alpha As Double, cos_beta As Double, cos_gamma As Double
Dim d As Double

d = dist1(pt1)

If d = 0 Then
dir_cosines2 = pt(0, 0, 0)
Exit Function
End If

cos_alpha = (pt2(0) - pt1(0)) / d
cos_beta = (pt2(1) - pt1(1)) / d
cos_gamma = (pt2(2) - pt1(2)) / d

dir_cosines2 = pt(cos_alpha, cos_beta, cos_gamma)
End Function

Function dir_angle(dir_cosine As Double) As Double
dir_angle = WorksheetFunction.Acos(dir_cosine)
dir_angle = rad2deg(dir_angle)
End Function

Function add_vectors(pt1() As Double, pt2() As Double) As Double()
add_vectors = pt(pt1(0) + pt2(0), pt1(1) + pt2(1), pt1(2) + pt2(2))
End Function

Function mult_vector(n As Double, pt1() As Double) As Double()
mult_vector = pt(n * pt1(0), n * pt1(1), n * pt1(2))
End Function

Sub test5()
Call Connect_Acad

pt1 = pt(2, 4, 6)
pt2 = pt(1, 9, 10)
line1 pt1
line1 pt2
line2 midpt1(pt1), midpt1(pt2)

Dim cosines() As Double
cosines = dir_cosines1(pt1)
pt3 = mult_vector(10, cosines)

'makes a line 10 in length along same line as pt1
line1 pt3

'alpha angle
Debug.Print dir_angle(cosines(0))
End Sub

Sub test6()
Call Connect_Acad

pt1 = pt(5, 1, 2)
pt2 = pt(1, 2, 3)
pt3 = add_vectors(pt1, pt2)

line1 pt1
line3 pt1, pt2
line1 pt3

acadApp.Update
End Sub