Automated Foundation Rebar Drawing Aug 2025

Drawn by Code
Is a picture worth a 1000 words?
Diagram or Text or Both?
I freely admit, this is a simple drawing example but it illustrates a working technique
Let’s make an automated diagram, using Excel, PyXLL, and Python. I built a VBA version of this code about 10 years ago. I converted it to a PyXLL macro in 2018. This week I revisited the code and found it incompatible with my current Microsoft 365 version of Excel. I had to change a few aspects of my PyXLL code.

Enough history, now to the present.

PREMISE

I will prepare a diagram showing the plan view of the mat in a spread foundation.

automated drawing

For the layperson:

Rebar is short for reinforcing bar.

In ACI (American Concrete Institute) terminology, “nominal” refers to the standard or intended size of a rebar, often based on its diameter. For example, #8 rebar has a nominal diameter of 8/8 inches, or 1 inch. Rebar sizes are designated by numbers, with each number representing the nominal diameter in eighths of an inch (e.g., #3 rebar is 3/8 inch diameter).

Typically, two grids of rebar are required: a top grid layer and a bottom grid layer. The bottom grid layer is designed for positive moment, the top grid layer is designed for negative moment. In my macro, I illustrate only one of the two grids. A full engineering spreadsheet would, of course, show both grids.

The foundation is specified by length and width. Rebar is specified by nominal size and maximum spacing. In an engineering drawing the number of rebar is also called out, for clarity.

I do not address the design procedure, only the drawing of the finished design.

Below, I offer a static image illustrating a typical rebar layout drawing. Note that this one is entirely sufficient; it’s not to scale and that’s okay, even preferable; it’s driven by Excel cell values; it was handmade using Excel; and it is easily modified for each new foundation design.

typical rebar layout diagram
This is a typical rebar layout diagram showing the essential elements

VIDEO

Here is a short video illustrating use of the macro.

Note that I simplify and shorten the input dialog, using only two prompts.

The first prompt asks for 3 parameters; the user responds with a space delimited entry of ‘Cover Xdim YDim’. The second prompt asks for 4 parameters; the user responds with a space delimited entry of ‘VBar Xspace HBar YSpace’. Obviously the macro parses the input thereby obtaining the parameter values.


## FOR EXAMPLE
#  ===========

Cover, Xdim, Ydim = [float(e) for e in rebarparameters.split()]
Immediately the diagram is drawn and labeled.

CODE CHANGES SINCE 2018

I mentioned having to update my code; here are snippets to explain.



##
## code updates from 2018 to 2025


##
## previous macro

horzbars = xl.Selection.Group()
horzbars.Name = "horz_bars"

vertbars = xl.Selection.Group()
vertbars.Name = "vert_bars"

allbars = xl.Selection.Group()
allbars.Name = "all_bars"


##
## current macro

horzbars = xl.Selection.ShapeRange.Group()
horzbars.Name = "horz_bars"

vertbars = xl.Selection.ShapeRange.Group()
vertbars.Name = "vert_bars"

allbars = xl.Selection.ShapeRange.Group()
allbars.Name = "all_bars"

MY PYXLL MACRO

In the folllowing code msxl is a personal python module. It contains my Excel drawing utility functions.


@xl_macro()
def vba_example():
    """
    [PyXLL] Draw rebar arrangement and callout from quick dialog box
    """
    xl = pyxll.xl_app()

    try:
        # access existing worksheet tab, if it exists
        myDocument = xl.Worksheets("draw")
    except:
        # add a new worksheet tab with the name "draw"
        myDocument = xl.workbook.addWorksheet("draw")

    what_scale = 3
    xoff = 150
    yoff = 150

    try:
        # delete previous foundation drawing shape
        # clean slate
        myDocument.Shapes("FoundationDrawing").Delete()
    except:
        pass

    ## INPUT FROM USER
    #  ===============

    # DRAWING params from user
    drawing_parameters = xl.InputBox("Drawing Parameters: Scale, Xoff, Yoff", Type=2)
    if drawing_parameters != "":
        what_scale, xoff, yoff = [float(e) for e in drawing_parameters.split()]

    # CONCRETE params from user
    rebarparameters = xl.InputBox("Foundation Parameters: Cover Xdim YDim", Type=2)

    strmylist = [e for e in rebarparameters.split()]
    # string variables
    strCover, strXdim, strYdim = strmylist
    # float variables
    mylist = [float(e) for e in rebarparameters.split()]
    Cover, Xdim, Ydim = mylist

    # REBAR params from user
    rebarparameters = xl.InputBox("Rebar Parameters: VBar Xspace HBar YSpace", Type=2)
    # string variables
    strmylist = [e for e in rebarparameters.split()]
    strVbar, strXspace, strHbar, strYspace = strmylist
    # float variables
    mylist = [float(e) for e in rebarparameters.split()]
    Vbar, Xspace, Hbar, Yspace = mylist

    ## HORIZONTAL BARS
    #  ===============

    # initialize list of line used in rebar drawing later
    mylines = []
    # initialize list of shapes used in selecting later
    myselection = []

    xstart = Cover
    xend = Xdim * 12 - Cover
    ystart = Cover
    yend = Ydim * 12 - Cover

    xstart_rebar = what_scale * (xstart) + xoff
    xend_rebar = what_scale * (xend) + xoff

    xstart_foundation = what_scale * (xstart - Cover) + xoff
    xend_foundation = what_scale * (xend + Cover) + xoff
    xdiff_foundation = xend_foundation - xstart_foundation

    # draw horz rebar
    ycount = rebarcount(ystart, yend, Yspace)
    # build line coordinates
    for n in rebarrange(ystart, yend, ycount):
        nq = what_scale * n + yoff
        mylines.append([xstart_rebar, nq, xend_rebar, nq])
    # draw lines
    for e in mylines:
        aaa = msxl.AddConnector(myDocument, e[0], e[1], e[2], e[3])
        msxl.SetLineProperties(aaa, 
                               visible=True, 
                               weight=0.75 * what_scale, 
                               forecolor=(0xFF0000))
        myselection.append(aaa)

    # gather horz bars, put them in a shape group, 
    # name the shape group
	
    selectreplaceflag = 0
    for e in myselection:
        if selectreplaceflag == 0:
            e.Select(Replace=True)
        else:
            e.Select(Replace=False)
        selectreplaceflag = 1
    horzbars = xl.Selection.ShapeRange.Group()
    horzbars.Name = "horz_bars"

    ## VERTICAL BARS
    #  =============

    mylines = []
    myselection = []

    ystart_rebar = what_scale * (ystart) + yoff
    yend_rebar = what_scale * (yend) + yoff

    ystart_foundation = what_scale * (ystart - Cover) + yoff
    yend_foundation = what_scale * (yend + Cover) + yoff
    ydiff_foundation = yend_foundation - ystart_foundation

    # draw vert rebar
    xcount = rebarcount(xstart, xend, Xspace)
    # build line coordinates
    for n in rebarrange(xstart, xend, xcount):
        nq = what_scale * n + xoff
        mylines.append([nq, ystart_rebar, nq, yend_rebar])
    # draw lines
    for e in mylines:
        aaa = msxl.AddConnector(myDocument, e[0], e[1], e[2], e[3])
        msxl.SetLineProperties(aaa, 
                               visible=True, 
                               weight=0.75 * what_scale, 
                               forecolor=(0xFF0000))
        myselection.append(aaa)

    # gather vert bars, put them in a shape group,
    # name the shape group
	
    selectreplaceflag = 0
    for e in myselection:
        if selectreplaceflag == 0:
            e.Select(Replace=True)
        else:
            e.Select(Replace=False)
        selectreplaceflag = 1
    vertbars = xl.Selection.ShapeRange.Group()
    vertbars.Name = "vert_bars"

    ## ALL BARS
    #  =============

    # gather all bars, put them in a shape group,
    # name the shape group
	
    horzbars.Select(Replace=True)
    vertbars.Select(Replace=False)
    allbars = xl.Selection.ShapeRange.Group()
    allbars.Name = "all_bars"

    # https://learn.microsoft.com/en-us/office/vba/api/excel.xlplacement    
    msxl.SetObjectProperties(allbars, placement="free")
    allbars.LockAspectRatio = -1  # msoTrue=-1

    ## CONCRETE
    #  ========

    # depict the foundation rectangle,
    # name the shape group

    fnd_concrete = msxl.AddShape(myDocument,
                                 1,
                                 xstart_foundation,
                                 ystart_foundation,
                                 xdiff_foundation,
                                 ydiff_foundation)
    fnd_concrete.Name = "foundation_concrete"
    fnd_concrete.LockAspectRatio = -1  # msoTrue=-1

    msxl.SetObjectFill(fnd_concrete,
                       fillvisible=False,
                       fillforecolor=(0xFFFFFF))
    fnd_concrete.ZOrder(1)  # msoSendToBack

    ## FOUNDATION
    #  ==========

    xl.Range("A1").Select
    xl.CutCopyMode = False  # UNselecting everything

    # gather all foundation aspects, put them in a shape group,
    # name the shape group
	
    allbars.Select(Replace=True)
    fnd_concrete.Select(Replace=False)
    allfoundation = xl.Selection.ShapeRange.Group()
    allfoundation.LockAspectRatio = -1  # msoTrue=-1
    allfoundation.Name = "all_foundation"

    ## TEXT BOX
    #  ========

    # determine placement of rebar spec textbox
    ulcornerx, ulcornery = xstart_rebar, yend_foundation + 10
    txt_box = msxl.AddTextbox(expr=myDocument, 
                              Orient=1, 
                              Left=ulcornerx, 
                              Top=ulcornery, 
                              Width=50, 
                              Height=12)
    txt_box.TextFrame2.TextRange.Characters.Text = "".join(
        [
            "[X (horz): ",
            strXdim,
            " feet]  #",
            strVbar,
            " @ ",
            strXspace,
            " (",
            str(xcount),
            " bars)",
            "\r",
            "[Y (vert): ",
            strYdim,
            " feet]  #",
            strHbar,
            " @ ",
            strYspace,
            " (",
            str(ycount),
            " bars)",
            "\r",
            "Cover: ",
            strCover,
            " inches",
        ]
    )
    msxl.SetTextFrame2Properties(txt_box,
                                 fontsize=15,
                                 fontbold=True,
                                 vertanchor="middle",
                                 horzanchor="left",
                                 wordwrap=False,
                                 autosize=True)
    msxl.SetObjectFill(txt_box, fillvisible=True, fillforecolor=(0xFFFF99))
    msxl.SetObjectProperties(txt_box, placement="free")

    txt_box.LockAspectRatio = -1  # msoTrue=-1
    txt_box.Name = "foundation_text"


    ## WRAP-UP
    #  =============
	
    # gather all drawing aspects, put them in a shape group,
    # name the shape group
	
    allfoundation.Select(Replace=True)
    txt_box.Select(Replace=False)
    allfoundationandlabel = xl.Selection.ShapeRange.Group()
    allfoundationandlabel.LockAspectRatio = -1  # msoTrue=-1
    allfoundationandlabel.Name = "FoundationDrawing"

    # https://learn.microsoft.com/en-us/office/vba/api/excel.xlplacement
    msxl.SetObjectProperties(allfoundationandlabel, placement="free")
	
    ## END OF PROGRAM

Leave a Reply

Your email address will not be published. Required fields are marked *