Point Data

Point Data

Here is the cumbersome addline method (ActiveX aka VBA) autocad knowledge network. I have simplified the point names.

Dim lineObj As AcadLine
Dim pt1(0 To 2) As Double
Dim pt2(0 To 2) As Double
pt1(0) = 1#: pt1(1) = 1#: pt1(2) = 0#
pt2(0) = 5#: pt2(1) = 5#: pt2(2) = 0#
Set lineObj = ThisDrawing.ModelSpace.AddLine(pt1, pt2)

When I first started autocad VBA I emailed an autodesk blog writer and suggested to him this wordiness practically eliminated any possibility of useful or popular parametrics and why not develop some simplified techniques in a column. He replied, first of all I have not used VBA in years, and secondly, I don’t have time to give you support. Alright fine. Stay away from my daughter. They seem to have solved the problem in dot net, but added another realm of issues. Here is the relevant line to create a Line object in (.NET), only one line of many.

Using acLine As Line = New Line(New Point3d(5, 5, 0), New Point3d(12, 3, 0))

You can do that in VBA. The std VBA help above is rewritten as –

Dim lineobj As AcadLine
Dim pt1() As Double, pt2() As Double
pt1 = pt(1, 1, 0)
pt2 = pt(5, 5, 0)
Set lineobj = acadDoc.ModelSpace.AddLine(pt1, pt2)

To do the shorthand method as in the (.NET) example with the inline assignment –

Dim lineobj As AcadLine
Set lineobj = acadDoc.ModelSpace.AddLine(pt(1, 1, 0), pt(5, 5, 0))

The (.NET) example also has 12 other lines to connect to the autocad unit. My program would also have about that number of lines, except I sub out once per session using a global object variable so the object keyword ThisDrawing becomes AcadDoc, and its invoked as

Connect_acad

Whats happening here is that the old method of declaring points is using a static array, and the new method is using a dynamic array. A static array cannot be assigned to a variable.

pt1 = pt2

Will give an error if pt1 was declared a static array, and it will be fine if it was a dynamic array. Pt2 can be either in this example.

The function to set point data then is always used, just as the (.NET) coders did with Point3D. There is no downside. The variable is always declared as a dynamic array.

Dim pt1() as double
pt1 = pt(1,2,3)

The function takes the xyz values and returns a dynamic point array used everywhere a static point would be used. In fact it declares a static array, but then passes that to a dynamic array. This little function opens up a world of productivity.

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

Wrapper functions to draw lines, circles, text, dimensions, etc can always pass point arrays rather than xyz values for simplicity. Its easier to develop the points in the calling function even if they need to be deconstructed in the called function.

A simple orthogonal 2D box, a very common item, is defined by two points on opposite corners. It requires two x values and two y values. The function is designed with an illustration that shows the box being drawn a particular direction, but in practice any two random points define one and only one orthogonal rectangle, providing they have neither x or y in common. The lightweight polyline is used in this case. Points are passed but then the xy values are extracted and formatted for the polyline array.


Sub mbox(p1() As Double, p2() As Double)
    Dim objent As AcadLWPolyline
    Dim pts(0 To 7) As Double
    
    Dim x0 As Double, x1 As Double
    Dim y0 As Double, y1 As Double
    
    x0 = p1(0)
    x1 = p2(0)
    y0 = p1(1)
    y1 = p2(1)
     
    pts(0) = x0: pts(1) = y0
    pts(2) = x1: pts(3) = y0
    pts(4) = x1: pts(5) = y1
    pts(6) = x0: pts(7) = y1
    Set objent = acadDoc.ModelSpace.AddLightWeightPolyline(pts)
    objent.Closed = True
    objent.Layer = "0"
End Sub

This illustrates how the 2D polyline works with an array of alternating x and y values. It doesnt use the point function, but the calling sub does with little problem.

Dim pt1() as double, pt2() as double
pt1 = pt(6, 1, 0)
pt2 = pt(2, 5, 0)
mbox pt1, pt2

The same thing could be drawn with lines with pts passed and used directly. I like objects that stay connected. The closed polyline takes an array twice the size of the number of vertexes consisting only of x and y values. The x and y values are the data used to draw. The parameters are the concept variables that push the x and y values around. For instance a sheet metal channel, would have 3 variables – the width, the leg, and the thickness of the material. Lets draw one where each leg can vary – 4 variables.

First step is to draw the object in the same rotation the program will use and label all x and y values. The easiest place to draw the object is with x0 and y0 at 0,0, so I assume that but you could draw it in place with a little more rigor. These type of sketches are not complete until dimensions, text, screws, notes, holes, other block details are added, and the whole assembly moved into a print border. I draw those using the xy data, and move the entire assembly into 8×10 print format all at once. If I have a list, I move that bunch over (in program) and start a new piece.

Looking at this sketch, we know we need a J_CHAN sub passing A, B, C and W for parameters.

The first thing the sub does is declare the x and y variables needed, and a dynamic array to put them into. x values then y values are specified in terms of A, B, C and W.

Sub J_CHAN2(A As Double, B As Double, C As Double, W As Double)
‘A is WIDTH, B is FRONT VERT, C is BACK VERT

Dim x0 As Double, y0 As Double
Dim x1 As Double, x2 As Double, x3 As Double
Dim y1 As Double, y2 As Double, y3 As Double
Dim pts As Variant

x0 = 0
y0 = 0

x1 = W
x2 = W + A
x3 = 2 * W + A

y1 = W
y2 = W + B
y3 = W + C

Now we have all the data to draw the object. The problem now is getting it to the 2D Polyline.
Addlightweightpolyline method takes an array of doubles. We used it with the Box sub. It has the same syntax as the old point method. Its a static array. It has the same cumbersome requirements. Every shape that has a different number of vertices requires the proper size array.

Here is the autocad help example. I added connect_acad and changed ThisDrawing to acadDoc to get it to run (from excel). This draws a 4-line squiggle, using 5 points (for some reason 2 segments are in line). So you need 10 places in the array, 0 to 9.


Sub Example_AddLightWeightPolyline()
    ' This example creates a lightweight polyline in model space.
    Call Connect_Acad
    
    Dim plineObj As AcadLWPolyline
    Dim points(0 To 9) As Double
    
    ' Define the 2D polyline points
    points(0) = 1: points(1) = 1
    points(2) = 1: points(3) = 2
    points(4) = 2: points(5) = 2
    points(6) = 3: points(7) = 2
    points(8) = 4: points(9) = 4
        
    ' Create a lightweight Polyline object in model space
    Set plineObj = acadDoc.ModelSpace.AddLightWeightPolyline(points)
    ZoomAll
    
End Sub

The easiest way to make an array in VBA is with the Array function. The array function returns a variant containing an array. The syntax is very simple. You do not have to index the locations.

Dim Ar as variant
Ar = Array(1,1,1,2,2,2,3,2,4,4)

The data is the same as above but the array is not the same. Polyline won’t accept it. “Invalid argument.” It’s a variant that contains an array. VBA won’t assign the variant to a dynamic array either. We have to step through it to convert it to an array of doubles that polyline will use. But that gives us a chance to write a sub that will accept an array of any length. So we can make our point list with the simple array function, then hand it off to a sub to draw.

Sub test_array()
    Call Connect_Acad
    Dim Ar As Variant

    Ar = Array(1, 1, 1, 2, 2, 2, 3, 2, 4, 4)
    
    draw_ar Ar
End Sub

Sub draw_ar(pt As Variant)
     Dim pt2() As Double
     Dim objent As AcadLWPolyline
     Dim i As Integer
     Dim lower As Integer, upper As Integer
     lower = LBound(pt)
     upper = UBound(pt)
     
     ReDim pt2(lower To upper)
     For i = lower To upper
     pt2(i) = pt(i)
     Next i
    
     Set objent = acadDoc.ModelSpace.AddLightWeightPolyline(pt2)
        ' objent.Closed = True
         objent.Update
 End Sub

I have the polyline not closed to duplicate the autocad help example. Now my draw sub will draw any list given to it of any length and I can randomly add pairs of numbers to the list to test it.

Lets go back to our J-Channel and make the array of x and y values with the Array function then pass it off to be drawn. Final working version here.

Sub test_chan()
Call Connect_Acad
Call J_CHAN2(4, 2, 3, 0.0625)
End Sub


Sub J_CHAN2(A As Double, B As Double, C As Double, W As Double)
    'A is WIDTH, B is FRONT VERT, C is BACK VERT
  
    Dim x0 As Double, y0 As Double
    Dim x1 As Double, x2 As Double, x3 As Double
    Dim y1 As Double, y2 As Double, y3 As Double
     
    Dim pts As Variant
    
    x0 = 0
    y0 = 0
 
    x1 = W
    x2 = W + A
    x3 = 2 * W + A
    
    y1 = W
    y2 = W + B
    y3 = W + C
    
    pts = Array(x0, y0, x3, y0, x3, y3, x2, y3, x2, y1, x1, y1, x1, y2, x0, y2, x0, y0)
    Call draw_array(pts)
    global_pline.Layer = "0"

acadApp.Update
End Sub


Sub draw_array(pt As Variant)
     Dim pt2() As Double
     Dim objent As AcadLWPolyline
     Dim i As Integer
     Dim lower As Integer, upper As Integer
     lower = LBound(pt)
     upper = UBound(pt)
     
     ReDim pt2(lower To upper)
     For i = lower To upper
     pt2(i) = pt(i)
     Next i
    
     Set objent = acadDoc.ModelSpace.AddLightWeightPolyline(pt2)
         objent.Closed = True
         objent.Update

     Set global_pline = objent
 End Sub

Point data starts with x and y values. X and Y and Z values are loaded into point arrays.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.