In 2D coordinates, AX + BY + C = 0 is the equation of a line. In 3D coordinates, this equation represents a plane. In 3D coordinates its not possible to specify a line by a single equation. A 3D line is represented by 3 equations, one for each x,y and z.

A straight line in space is completely determined by two points. It is also completely determined with a single point and a set of direction numbers. The direction numbers are the difference of the coordinates over any segment. Direction numbers come in sets of three. Its the same idea as a vector. A line has an infinite amount of direction number sets, all of them proportional. Just as you can multiply a vector by a scalar, and obtain another vector parallel but with a different length, you can multiply direction numbers by a scalar, call it t, and obtain further points on the same line.

If two points are given, (x1,y1,z1) and (x2,y2,z2), direction numbers are (x2-x1, y2-y1, z2-z1). These are often referred to as (a,b,c).

Either point can be used for the given point

X = x1 + at

Y = y1 + bt

Z = z1 + ct

To create an unending line in both directions, t takes on values between negative and positive infinity.

if we take an example, let one point P1 be the origin and the other point be (2,3,4). use P1 for the given point and (2,3,4) for (a,b,c)

X = 2t

Y = 3t

Z = 4t

the length of a line segment is the sq root of the sum of the coordinate deltas squared, so Len (2,3,4) is 29^1/2

when t = 0, the point on the line is the origin. When t=1, the point is (2,3,4).

when

so if

when the line segment is 1, the coordinates are the direction cosines. the angle between the line and each of the coordinate axes can be found by taking the ArcCosine.

to put an arrowhead on a 3D vector, i insert an arrowhead block. I wanted to draw and do a revolve, but i was not initially able to find the activex method for revolve, so insert a block is the standby. i drew the cone shape the same size as dimension arrowheads so the scale factor works in a similar way. the insertion point is the head of the vector. we need the angle. i pass a direction vector, which is a parallel vector any length. normally i will just pass the same vector, but sometimes like when constructing an XYZ axes it is just as convenient to pass a unit vector.

Sub arr(pt1() As Double, D() As Double)

‘3D arrow

‘pt1 is location of the arrow

‘D is direction vector

the direction cosines of the direction vector are the familiar array of 3 doubles.

Dim dir_cos() As Double ‘direction cosines

dir_cos = ret_3D_angle(D)

the function ret_3D_angle takes one parameter, the direction vector, calculates the length, divides the x,y,z values by the length, and returns all 3 together in an array, just like a point.

the direction cosine for the x axis – the x coordinate for the direction vector at the place where the length is one – is used and the angle found for autocad to use later.

Dim alpha As Double

alpha = WorksheetFunction.Acos(dir_cos(0))

we have not passed in the actual tail coordinate of the vector we are trying to arrow. we have passed in the head coordinate and a vector parallel. the direction vector is positionless. its just 3 numbers. if we subtract those from the head coordinates, we will have a second point on the vector.

when we do that we have enough coordinates to change the user coordinate system, ucs in autocad, to a plane defined by the two lines, the vector itself and a line from the tail point just calculated parallel to the x-axis.

First we insert the arrowhead at rotation zero at the world coordinate system. then change the user coordinate system to the one defined by our vector and a line parallel to the x-axis. when you rotate an object, it rotates around a line perpendicular to the user coordinate system. so in effect by changing the user coordinate system, we have already made one rotation, even though we have not applied it yet. now rotate the arrowhead by the insertion point through alpha radians that we previously calculated. that completes the 3D arrow rotation.

Even though there are 3 angles from a vector to each of the axes, any two of them determine the third.

here is a diagram i did a while back on the arrowhead rotation problem.

x1,y1, z1 is any valid point on the vector which we have found above. to create a new ucs, a new origin is located, then a point on the new x-axis, and a point on the new y-axis. they must form a right angle. the new origin can be assembled from the head and tail coordinates. the new x-axis point can just add one value for x, and the new y-axis can use the head coordinates. some special error checking has to occur when the arrow is on the x-axis.

Sub arr(pt1() As Double, D() As Double) '3D arrow 'pt1 is location of the arrow 'D is direction vector Dim x1 As Double, y1 As Double, z1 As Double Dim x2 As Double, y2 As Double, z2 As Double Dim origin() As Double, xAxis() As Double, yAxis() As Double Dim dir_cos() As Double 'direction cosines dir_cos = ret_3D_angle(D) Dim alpha As Double alpha = WorksheetFunction.Acos(dir_cos(0)) Dim blkref As AcadBlockReference Dim blkname As String blkname = "Ar_Head3D" If sc = 0 Then sc = 1 'need an illustration 'pt1 is the location for the arrowhead 'D is the direction vector 'the new origin is x from pt1 and y and z calculated from tail of D 'transfer pt1 to x2,y2,z2 x2 = pt1(0) y2 = pt1(1) z2 = pt1(2) ' direction vector is positionless ' so we in effect put it at head and find tail x1 = x2 - D(0) y1 = y2 - D(1) z1 = z2 - D(2) ' the new origin and new xaxis can be calculated ' the new yaxis is the tip of the arrow origin = pt(x2, y1, z1) xAxis = pt(x2 + 1, y1, z1) yAxis = pt1 set_wcs ' make sure we insert at world ucs Set blkref = acadDoc.ModelSpace.InsertBlock(pt1, blkname, sc, sc, sc, 0) 'error when d(1) = 0 ucs yaxis is same as origin 'when alpha = 0 dont need to rotate 'when alpha = pi dont need to change ucs 'On Error Resume Next If dir_cos(0) = 1 Then Exit Sub If dir_cos(0) <> -1 Then Call set_ucs(origin, xAxis, yAxis, "UCS_alpha") End If blkref.Rotate pt1, alpha set_wcs End Sub Function ret_3D_angle(D() As Double) As Double() 'D is direction vector 'returns an array of 3 doubles that contain the direction cosines Dim vector_len As Double Dim pt1() As Double Dim A As Double, B As Double, C As Double vector_len = leng(D) If vector_len = 0 Then MsgBox "zero vector in ret_3D_angle" Exit Function End If A = D(0) / vector_len B = D(1) / vector_len C = D(2) / vector_len pt1 = pt(A, B, C) ret_3D_angle = pt1 End Function Sub set_ucs(origin() As Double, xAxis() As Double, yAxis() As Double, strName As String) Dim ucsObj As AcadUCS Set ucsObj = acadDoc.UserCoordinateSystems.Add(origin, xAxis, yAxis, strName) acadDoc.ActiveUCS = ucsObj End Sub Sub set_wcs() ' Call Connect_Acad Dim ucsObj As AcadUCS Dim pt0() As Double, ptx() As Double, pty() As Double pt0 = pt(0, 0, 0) ptx = pt(1, 0, 0) pty = pt(0, 1, 0) Set ucsObj = acadDoc.UserCoordinateSystems.Add(pt0, ptx, pty, "World") acadDoc.ActiveUCS = ucsObj End Sub