Sub-routines and functions should be single purpose, they should list inputs and outputs in comments at the top of the file, and they should print on one page. Thats what I learned at school. The sub that calculates parametric points though tends to turn into a long list of tasks because the point values are so useful. They are used to hang dimensions, notes, blocks, associate with other parts, move into position on the page, and on and on. Another thing sometimes making it difficult to break up the laundry list is that functions can only return one value.
Small pieces are easier to manage than one big. Irrelevant but necessary details are hidden. Compromises then are these. The calling sub we will call main (not literally). The polyline draw routine is a sub of main. Anything that does not require point values developed in the draw sub will sub from main. Anything that must use the point values in polyline draw can tack on to polyline draw or sub from it. Functions (actually subs) that need to set up more than one value can use global variables. Global variables are a useful tool.
Dimensions hang from the points of the object. It’s hard to remove the dimension sub from the geometry sub entirely, but they can be reduced to the essential. One of the complications of dimensioning parts that can change size is locating the dimensions. They have to move with the part. A big part of this post is showing how to do that. The array of geometry points can be searched in a loop to get a bounding box, then standard distances off the bounding box can be calculated for locating dimension lines.
To illustrate how dimensions work – the part is outside corner, abbrev OS_CRNR
The xy data are calculated from the sketch. The array is made. The array is passed off to be drawn.
Dim pts As Variant
x0 = 0
x1 = W
x2 = W + B – 0.375
x3 = W + B
x4 = x2
x5 = 0.125
x6 = 0.125 + W
y0 = 0
y1 = W
y2 = W + A – 0.375
y3 = W + A
y4 = y2
y5 = 0.125
y6 = 0.125 + W
pts = Array(x0, y0, x2, y0, x3, y5, x3, y6, x4, y1, x1, y1, x1, y4, x6, y3, x5, y3, x0, y2)
dimloc LL, UR, sc
The array can then be traversed to find its minimum and maximum values, and a bounding box, defined by lower left point and upper right point, can be calculated. Since there are two values to be returned, global variables are used.
Public LL() As Double
Public UR() As Double
Sub bound_box(pts) 'input is variant array of pts created for 2D polyline 'output is global LL and UR points of bounding box Dim i As Integer Dim lower As Integer, upper As Integer Dim xmin As Double, xmax As Double Dim ymin As Double, ymax As Double lower = LBound(pts) upper = UBound(pts) xmin = pts(0) xmax = pts(0) For i = 0 To upper - 1 Step 2 If xmin > pts(i) Then xmin = pts(i) If xmax < pts(i) Then xmax = pts(i) Next i ymin = pts(1) ymax = pts(1) For i = 1 To upper Step 2 If ymin > pts(i) Then ymin = pts(i) If ymax < pts(i) Then ymax = pts(i) Next i 'global pt variables set LL = pt(xmin, ymin, 0) UR = pt(xmax, ymax, 0) End Sub
Now that the corners of a virtual box are obtained, it can be used to situate dimension lines. These have to be calculated in relation to whatever scale is used. Thats a separate determination in the program. Here I am using global variable sc which is set to 2. The distance between dimension lines is one half inch. Those two numbers are multiplied.
Linear Dimensions in autocad vba need three inputs – two endpoints and a location for the dimension line. We are making standard locations on all 4 sides for the dimension lines. They are global variables. They are our common dynamic point array. They are calculated a set distance from the part and almost never have to be moved after the fact.
Bound_box returns the extents of the part. The sub dimloc uses the extents for input, LL and UR, and the scale sc and sets the location variables for this particular part.
Sub dimloc(LL() As Double, UR() As Double, sc As Integer) 'input is lower and upper corner points of geometry 'output are global midpoint locations of dimension lines ' VT1, VT2, VT3, VT4, HZ1, HZ2, HZ3, HZ4 Dim x As Double, y As Double Dim A As Double A = 0.5 * sc x = (LL(0) + UR(0)) / 2 y = LL(1) - A * 2 hz1 = pt(x, y, 0) y = LL(1) - A hz2 = pt(x, y, 0) y = UR(1) + A hz3 = pt(x, y, 0) y = UR(1) + 2 * A hz4 = pt(x, y, 0) x = LL(0) - A * 2 y = (LL(1) + UR(1)) / 2 vt1 = pt(x, y, 0) x = LL(0) - A vt2 = pt(x, y, 0) x = UR(0) + A vt3 = pt(x, y, 0) x = UR(0) + 2 * A vt4 = pt(x, y, 0) LL2 = pt(vt1(0), hz1(1), 0) UR2 = pt(vt4(0), hz4(1), 0) End Sub
And then finally we use those variables to create dimensions. We do that in the sub where the points are using the xy data available. The call is simple, the details are hidden away. Wrapper subs for the dimension are used. I use one for each vertical and horizontal dimensions with the rotations built-in.
Here is the calling sub OS_CRNR (main), OS_CRNR_draw, and the dimensioning wrappers.
Sub OS_CRNR(A As Double, B As Double, W As Double) Call OS_CRNR_draw(A, B, W) do_os_crnr_note flat_dim = A + B Do_bend_det Do_border Do_title Etc Etc End Sub Sub OS_CRNR_draw(A As Double, B As Double, W As Double) Dim x0 As Double, y0 As Double Dim x1 As Double, x2 As Double, x3 As Double, x4 As Double, x5 As Double, x6 As Double Dim y1 As Double, y2 As Double, y3 As Double, y4 As Double, y5 As Double, y6 As Double Dim pts As Variant x0 = 0 x1 = W x2 = W + B - 0.375 x3 = W + B x4 = x2 x5 = 0.125 x6 = 0.125 + W y0 = 0 y1 = W y2 = W + A - 0.375 y3 = W + A y4 = y2 y5 = 0.125 y6 = 0.125 + W pts = Array(x0, y0, x2, y0, x3, y5, x3, y6, x4, y1, x1, y1, x1, y4, x6, y3, x5, y3, x0, y2) Call draw_array(pts) global_pline.Layer = "0" bound_box pts dimloc LL, UR, sc pt1 = pt(x1, y1, 0) pt2 = pt(x5, y3, 0) pt3 = pt(x3, y5, 0) pt4 = pt(x0, y3 - 0.625, 0) pt5 = pt(x3 - 0.625, y0, 0) dimv pt1, pt2, vt1 dimh pt1, pt3, hz1 dimv pt4, pt2, vt2 dimh pt5, pt3, hz2 do_screw pt4, 0 do_screw pt5, PI / 2 acadApp.Update End Sub Sub dimv(pt1() As Double, pt2() As Double, dimlocpt() As Double) Dim dimObj As AcadDimRotated Set dimObj = acadDoc.ModelSpace.AddDimRotated(pt1, pt2, dimlocpt, PI / 2) dimObj.Layer = "DIM" End Sub Sub dimh(pt1() As Double, pt2() As Double, dimlocpt() As Double) Dim dimObj As AcadDimRotated Set dimObj = acadDoc.ModelSpace.AddDimRotated(pt1, pt2, dimlocpt, 0) dimObj.Layer = "DIM" End Sub
see the previous post for the essential PT(x,y,z) function that creates point arrays.
global variables that dimloc sets look like this (below). LL2 and UR2 are bounding box of the part and its dimensions, for the purpose of moving it into position on a 8×10 border. I have made peace with the idea that there can be too many global variables. They help solve the problem of passing values between smaller programs.
‘vert dim line locations left to right
Public vt1() As Double
Public vt2() As Double
Public vt3() As Double
Public vt4() As Double
‘horiz dim line locations bottom to top
Public hz1() As Double
Public hz2() As Double
Public hz3() As Double
Public hz4() As Double
Public LL() As Double
Public UR() As Double
Public LL2() As Double
Public UR2() As Double