Parametric Dimensioning

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)
Call draw_array(pts)

bound_box pts
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