Autocad VBA Parametrics – 1 – Wrapper functions

Sometimes it takes a long time to make something simple. Creating wrapper subroutines makes large parametric programs cleaner and easier to read, allowing them to get larger and more useful. If you straightforwardly code each routine containing all the details it uses, you soon reach a point where the program is too complex looking to modify. Wrapper routines delegate the details of the drawing and make the flow of the calling programs easier to follow.

The ADDLINE method in Autocad VBA requires an array of 3 doubles for each endpoint of the line.

Dim lineobj as AcadLine
Dim pt1(0 To 2) As Double
Dim pt2(0 To 2) As Double
pt1(0) = 2: pt1(1) = 3: pt1(2) = 0
pt2(0) = 40: pt2(1) = 50: pt2(2) = 0
Set lineobj = acadDoc.ModelSpace.AddLine(pt1, pt2)

By contrast the same thing can be done in autolisp with one line of code.

(command “line” (list 2 3) (list 4 5) “”)

Autocad VBA does not allow any shortcuts. Every line drawn has to use a dimensioned named assigned array of 3 doubles.

An Autocad VBA parametric drawing program would quickly require too many points to be practical. Wrapper functions are the solution. I am using the term in an informal way to indicate wrapping a VBA Autocad method to make it easier to use. Here is a simple line wrapper and how it is called.

call line(2, 3, 40, 50)

 Sub line(x1 As Double, y1 As Double, x2 As Double, y2 As Double)
Dim lineobj As AcadLine
Dim pt1(0 To 2) As Double
Dim pt2(0 To 2) As Double
pt1(0) = x1: pt1(1) = y1: pt1(2) = 0
pt2(0) = x2: pt2(1) = y2: pt2(2) = 0
Set lineobj = acadDoc.ModelSpace.AddLine(pt1, pt2)
End Sub

Every Autocad VBA object is a candidate for one or more wrappers. The point command in autocad is not used very often in design (its very useful in the graphing calculator), but it could be easily simplified.
Call draw_point(1,3,0)

Sub draw_point(x1 As Double, y1 As Double, z1 As Double)
Dim pointobj As AcadPoint
Dim pt1(0 To 2) As Double
pt1(0) = x1: pt1(1) = y1: pt1(2) = z1
Set pointobj = acadDoc.ModelSpace.AddPoint(pt1)
End Sub

An array of 3 doubles is Autocad VBA’s normal way of specifying a point location used by dozens of different objects. We can make a wrapper to aid making this array. When passing arrays as arguments to a subroutine they are always passed by reference – any changes made to the array in the called program are reflected in the calling program. Unfortunately we cannot get the wrapper to dimension the array for us, but we can simplify the values assignment a little. It does help when a lot of points are being set up.

Dim pt2(0 to 2) as Double
Call initpt(pt2, 2, 4, 0)

Sub initpt(ByRef ptn() As Double, val1 As Double, val2 As Double, val3 As Double)
ptn(0) = val1: ptn(1) = val2: ptn(2) = val3
End Sub

The ADDLIGHTWEIGHTPOLYLINE method requires a single array of doubles, one value for each x and y. A line with two points would require an array with 4 values.

Dim plineobj As AcadLWPolyline
Dim pt(1 To 4) As Double
pt(1) = 2: pt(2) = 3: pt(3) = 40: pt(4) = 50
Set plineobj = acadDoc.ModelSpace.AddLightWeightPolyline(pt)

The LightWeightPolyline method can be wrapped in a box routine. Box is drawn from lower left counterclockwise. The last segment is made with the closed property. In this case a layer is specified. It could be left out of the routine or made optional.
Call mbox(0, 0, L, W, “Hidden”)

Sub mbox(x1 As Double, y1 As Double, x2 As Double, y2 As Double, strlayer As String)
    Dim objent As AcadLWPolyline
    Dim pt(1 To 8) As Double
    pt(1) = x1: pt(2) = y1
    pt(3) = x2: pt(4) = y1
    pt(5) = x2: pt(6) = y2
    pt(7) = x1: pt(8) = y2
    Set objent = acadDoc.ModelSpace.AddLightWeightPolyline(pt)
    objent.Closed = True
    objent.layer = strlayer
End Sub

Rectangular boxes show up a lot in any design. Any plane figure with a known number of vertexes could be hard coded as above. If you have a parametric application that often uses a notched rectangle you would use a polyline wrapper expecting 6 points. Here is how the hardcoded 6 point polyline sub is coded. You can see the 12 inputs are starting to get tedious. This 6 pointed figure has 12 inputs and the 4 pointed figure above has 4 inputs because this figure does not have to have rectangular angles, it simply draws 6 points. the box above is assumed to be square with the coordinate system.

Sub test_p6()
Call connect_acad
Dim L As Double, W As Double, A As Double, B As Double
L = 72
W = 24
A = 12
B = 18
Call p6_box(0, 0, L - B, 0, L - B, A, L, A, L, W, 0, W)
End Sub

Sub p6_box(p1 As Double, p2 As Double, p3 As Double, p4 As Double, p5 As Double, p6 As Double, _
p7 As Double, p8 As Double, p9 As Double, p10 As Double, p11 As Double, p12 As Double)

    Dim objent As AcadLWPolyline
    Dim pt(1 To 12) As Double
    pt(1) = p1: pt(2) = p2
    pt(3) = p3: pt(4) = p4
    pt(5) = p5: pt(6) = p6
    pt(7) = p7: pt(8) = p8
    pt(9) = p9: pt(10) = p10
    pt(11) = p11: pt(12) = p12
    Set objent = acadDoc.ModelSpace.AddLightWeightPolyline(pt)
    objent.Closed = True
End Sub

The straightforward method to draw complex polyline figures would initially be coded all in one sub. The array would be dimensioned then loaded with values and immediately be given to the AddPoly method. This is a closed figure with 16 points.

 Dim objent As AcadLWPolyline
    Dim pt(1 To 32) As Double
    pt(1) = 1: pt(2) = 0.21875
    pt(3) = 0: pt(4) = 0.21875
    pt(5) = 0: pt(6) = 0
    pt(7) = W - 1.25: pt(8) = 0
    pt(9) = W - 1.0625: pt(10) = 0.1875
    pt(11) = W: pt(12) = 0.1875
    pt(13) = W: pt(14) = 0.40625
    pt(15) = W - 0.875: pt(16) = 0.40625
    pt(17) = W - 0.875: pt(18) = 0.34375
    pt(19) = W - 0.0625: pt(20) = 0.34375
    pt(21) = W - 0.0625: pt(22) = 0.25
    pt(23) = W - 1.08839: pt(24) = 0.25
    pt(25) = W - 1.27589: pt(26) = 0.0625
    pt(27) = 0.0625: pt(28) = 0.0625
    pt(29) = 0.0625: pt(30) = 0.15625
    pt(31) = 1: pt(32) = 0.15625
    Set objent = acadDoc.ModelSpace.AddLightWeightPolyline(pt)
    objent.Closed = True

A general method can be devised using a generic wrapper that tests the length of the array passed. However the poly method only accepts an array of doubles, and there is no way to conveniently construct an array of doubles except by declaring the index numbers of each value as above. The array function is easier to construct, but it only works with a variant declared. That is what we will use to construct the point list, then convert it in the wrapper, which can accept an array of any size.

Sub test_draw_array()
    Call connect_acad
    Dim W As Double
    W = 24
    Dim pt As Variant
    pt = Array(1, 0.21875, 0, 0.21875, _
                0, 0, W - 1.25, 0, _
                W - 1.0625, 0.1875, W, 0.1875, _
                W, 0.40625, W - 0.875, 0.40625, _
                W - 0.875, 0.34375, W - 0.0625, 0.34375, _
                W - 0.0625, 0.25, W - 1.08839, 0.25, _
                W - 1.27589, 0.0625, 0.0625, 0.0625, _
                0.0625, 0.15625, 1, 0.15625)
    Call draw_array(pt)
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
End Sub
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s