Skip to content
Snippets Groups Projects
Blocks.py 67.4 KiB
Newer Older
  • Learn to ignore specific revisions
  •                [dims['e'] + row.EdgeOffset / r1 - edgrt, WallBoundaries]]
    
        # Same as edgetop,  but for the bottms of the rows
        edgebtm = [[dims['s'] + row.EdgeOffset / r1 + edgrt, WallBoundaries],
                   [dims['e'] + row.EdgeOffset / r1 - edgrt, WallBoundaries]]
    
    
        # set up some useful values for the top and bottom of the rows.
    
        rowTop = row.z + row.h / 2
        rowBtm = row.z - row.h / 2
    
            # check the top and bottom of the row, looking at the opening from the right
    
            e = [hole.edgeS(rowTop, -1), hole.edgeS(rowBtm, -1)]
    
            # If either one hit the opening, make split points for the left side of the opening.
            if e[0] or e[1]:
                e += [hole.edgeS(rowTop, 1), hole.edgeS(rowBtm, 1)]
    
                # If one of them missed for some reason, set that value to
                # the middle of the opening.
    
                for i, pos in enumerate(e):
                    if pos is None:
                        e[i] = hole.x
    
    
                # add the intersects to the list of edge points
    
                edgetop.append([e[0], hole])
                edgetop.append([e[2], hole])
                edgebtm.append([e[1], hole])
                edgebtm.append([e[3], hole])
    
    
        # We want to make the walls in order, so sort the intersects.
        # This is where you would want to remove edge points that are out of order
    
        # so that you don't get the "oddity where overlapping openings
        # create blocks inversely" problem
    
        # Note: sort ended up comparing function pointers
        # if both Openings and Slots were enabled with Repeats in one of them
        try:
            edgetop.sort(key=lambda x: x[0])
            edgebtm.sort(key=lambda x: x[0])
        except Exception as ex:
            debug_prints(func="rowProcessing",
                         text="Sorting has failed", var=ex)
    
        # these two loops trim the edges to the limits of the wall.
        # This way openings extending outside the wall don't enlarge the wall.
    
                if ((edgetop[-1][0] > dims['e'] + row.EdgeOffset / r1) or
                  (edgebtm[-1][0] > dims['e'] + row.EdgeOffset / r1)):
    
                else:
                    break
            except IndexError:
                break
        # still trimming the edges...
    
                if ((edgetop[0][0] < dims['s'] + row.EdgeOffset / r1) or
                  (edgebtm[0][0] < dims['s'] + row.EdgeOffset / r1)):
    
                else:
                    break
            except IndexError:
                break
    
        # make those edge blocks and rows!  Wooo!
        # This loop goes through each section, (a pair of points in edgetop)
        # and places the edge blocks and inbetween normal block zones into the row object
        for OpnSplitNo in range(int(len(edgetop) / 2)):
            # left edge is edge<x>[2*OpnSplitNo], right edge edgex[2*OpnSplitNo+1]
            leftEdgeIndex = 2 * OpnSplitNo
            rightEdgeIndex = 2 * OpnSplitNo + 1
    
    
            # get the openings, to save time and confusion
            leftOpening = edgetop[leftEdgeIndex][1]
            rightOpening = edgetop[rightEdgeIndex][1]
    
    
            # find the difference between the edge top and bottom on both sides
    
            LTop = edgetop[leftEdgeIndex][0]
            LBtm = edgebtm[leftEdgeIndex][0]
            RTop = edgetop[rightEdgeIndex][0]
            RBtm = edgebtm[rightEdgeIndex][0]
    
            LDiff = LBtm - LTop
            RDiff = RTop - RBtm
    
            # which is further out on each side, top or bottom?
    
                LNerEdge = LBtm  # the nearer edge left
                LEB = 1          # Left Edge Boolean, set to 1 if furthest edge is top, -1 if it is bottom
    
                RNerEdge = RBtm  # the nearer edge right
                REB = 1  # Right Edge Boolean, set to 1 if furthest edge is top, -1 if it is bottom
    
                REB = -1  # Right Edge Boolean, set to 1 if furthest edge is top, -1 if it is bottom
    
            # The space between the closest edges of the openings in this section of the row
    
            # The mid point between the nearest edges
            InnerMid = (RNerEdge + LNerEdge) / 2
    
            # maximum distance to span with one block
            MaxWid = (settings['w'] + settings['wv']) / r1
    
            # check the left and right sides for wedge blocks
            # Check and run the left edge first
            # find the edge of the correct side, offset for minimum block height.  The LEB decides top or bottom
            ZPositionCheck = row.z + (row.h / 2 - settings['hm']) * LEB
    
            # edgeS may return "None"
            LeftWedgeEdge = leftOpening.edgeS(ZPositionCheck, 1)
    
    
            if (abs(LDiff) > AveWid) or (not LeftWedgeEdge):
    
                # make wedge blocks
                if not LeftWedgeEdge:
                    LeftWedgeEdge = leftOpening.x
    
                wedgeBlocks(row, leftOpening, LeftWedgeEdge, LNerEdge, LEB, r1)
    
                # set the near and far edge settings to vertical, so the other edge blocks don't interfere
                LTop, LBtm = LNerEdge, LNerEdge
    
            # Now do the wedge blocks for the right, same drill... repeated code?
            # find the edge of the correct side, offset for minimum block height.  The REB decides top or bottom
            ZPositionCheck = row.z + (row.h / 2 - settings['hm']) * REB
    
            # edgeS may return "None"
            RightWedgeEdge = rightOpening.edgeS(ZPositionCheck, -1)
    
            if (abs(RDiff) > AveWid) or (not RightWedgeEdge):
    
                # make wedge blocks
                if not RightWedgeEdge:
                    RightWedgeEdge = rightOpening.x
    
                wedgeBlocks(row, rightOpening, RNerEdge, RightWedgeEdge, REB, r1)
    
                # set the near and far edge settings to vertical, so the other edge blocks don't interfere
                RTop, RBtm = RNerEdge, RNerEdge
    
            # Check to see if the edges are close enough toegther to warrant a single block filling it
    
                # if this is true, then this row is just one block!
                x = (LNerEdge + RNerEdge) / 2.
    
                ThisBlockDepth = rndd() * settings['dv'] + settings['d']
    
                BtmOff = LBtm - LNerEdge
                TopOff = LTop - LNerEdge
    
                ThisBlockOffsets = [[BtmOff, 0, 0]] * 2 + [[TopOff, 0, 0]] * 2
    
                BtmOff = RBtm - RNerEdge
                TopOff = RTop - RNerEdge
    
                ThisBlockOffsets += [[BtmOff, 0, 0]] * 2 + [[TopOff, 0, 0]] * 2
    
                bevel = leftOpening.edgeBev(rowTop)
                bevelBlockOffsets(ThisBlockOffsets, bevel, 1)
                bevel = rightOpening.edgeBev(rowTop)
                bevelBlockOffsets(ThisBlockOffsets, bevel, -1)
    
                row.BlocksEdge.append([x, row.z, w, row.h, ThisBlockDepth, ThisBlockOffsets])
    
                continue
    
            # it's not one block, must be two or more
            # set up the offsets for the left
            BtmOff = LBtm - LNerEdge
            TopOff = LTop - LNerEdge
    
            leftOffsets = [[BtmOff, 0, 0]] * 2 + [[TopOff, 0, 0]] * 2 + [[0] * 3] * 4
    
            bevelL = leftOpening.edgeBev(rowTop)
            bevelBlockOffsets(leftOffsets, bevelL, 1)
            # and now for the right
            BtmOff = RBtm - RNerEdge
            TopOff = RTop - RNerEdge
    
            rightOffsets = [[0] * 3] * 4 + [[BtmOff, 0, 0]] * 2 + [[TopOff, 0, 0]] * 2
    
            bevelR = rightOpening.edgeBev(rowTop)
            bevelBlockOffsets(rightOffsets, bevelR, -1)
            # check to see if it is only two blocks
    
            if (InnerDiff < MaxWid * 2):
                # this row is just two blocks! Left block, then right block
                # div is the x position of the dividing point between the two bricks
                div = InnerMid + (rndd() * settings['wv']) / r1
    
                # set the grout distance, since we need grout separation between the blocks
    
                grt = (settings['g'] + rndc() * settings['gv']) / r1
                # set the x position and width for the left block
                x = (div + LNerEdge) / 2 - grt / 4
                w = (div - LNerEdge) - grt / 2
                ThisBlockDepth = rndd() * settings['dv'] + settings['d']
                # For reference: EdgeBlocks = [[x, z, w, h, d, [corner offset matrix]], [etc.]]
                row.BlocksEdge.append([x, row.z, w, row.h, ThisBlockDepth, leftOffsets])
                # Initialize for the block on the right side
                x = (div + RNerEdge) / 2 + grt / 4
                w = (RNerEdge - div) - grt / 2
                ThisBlockDepth = rndd() * settings['dv'] + settings['d']
                row.BlocksEdge.append([x, row.z, w, row.h, ThisBlockDepth, rightOffsets])
    
            # program should only get here if there are more than two blocks in the row, and no wedge blocks
            # make Left edge block
            # set the grout
            grt = (settings['g'] + rndc() * settings['gv']) / r1
            # set the x position and width for the left block
    
            widOptions = [settings['w'], bevelL + settings['wm'], leftOpening.ts]
            baseWid = max(widOptions)
    
            w = (rndd() * settings['wv'] + baseWid + row. EdgeOffset)
    
            widOptions[0] = settings['wm']
            widOptions[2] = w
            w = max(widOptions) / r1 - grt
    
            x = w / 2 + LNerEdge + grt / 2
            BlockRowL = x + w / 2
            ThisBlockDepth = rndd() * settings['dv'] + settings['d']
            row.BlocksEdge.append([x, row.z, w, row.h, ThisBlockDepth, leftOffsets])
    
            # make Right edge block
            # set the grout
            grt = (settings['g'] + rndc() * settings['gv']) / r1
            # set the x position and width for the left block
    
            widOptions = [settings['w'], bevelR + settings['wm'], rightOpening.ts]
            baseWid = max(widOptions)
    
            w = (rndd() * settings['wv'] + baseWid + row.EdgeOffset)
    
            widOptions[0] = settings['wm']
            widOptions[2] = w
            w = max(widOptions) / r1 - grt
    
            x = RNerEdge - w / 2 - grt / 2
            BlockRowR = x - w / 2
            ThisBlockDepth = rndd() * settings['dv'] + settings['d']
            row.BlocksEdge.append([x, row.z, w, row.h, ThisBlockDepth, rightOffsets])
    
            row.RowSegments.append([BlockRowL, BlockRowR])
    
    def plan(Thesketch, oldrows=0):
    
        __doc__ = """\
        The 'plan' function takes the data generated by the sketch function and the global settings
        and creates a list of blocks.
        It passes out a list of row heights, edge positions, edge blocks, and rows of blocks.
        """
        # if we were passed a list of rows already, use those; else make a list.
    
        if oldrows:
            rows = oldrows
    
            # rows holds the important information common to all rows
            # rows = [list of row objects]
    
            # splits are places where we NEED a row division, to accomidate openings
            # add a split for the bottom row
            splits = [dims['b'] + settings['hb']]
    
            # add a split for each critical point on each opening
            for hole in Thesketch:
                splits += hole.crits()
    
            # and, a split for the top row
            splits.append(dims['t'] - settings['ht'])
    
            # divs are the normal old row divisions, add them between the top and bottom split
            divs = fill(splits[0], splits[-1], settings['h'], settings['hm'] + settings['g'], settings['hv'])[1: -1]
    
            # remove the divisions that are too close to the splits, so we don't get tiny thin rows
            for i in range(len(divs) - 1, -1, -1):
    
                for j in range(len(splits)):
                    diff = abs(divs[i] - splits[j])
    
                    if diff < (settings['h'] - settings['hv'] + settings['g']):
    
            # now merge the divs and splits lists
    
            # add bottom and/or top points, if bottom and/or top row heights are more than zero
            if settings['hb'] > 0:
                divs.insert(0, dims['b'])
            if settings['ht'] > 0:
                divs.append(dims['t'])
    
            # trim the rows to the bottom and top of the wall
            if divs[0] < dims['b']:
                divs[:1] = []
            if divs[-1] > dims['t']:
                divs[-1:] = []
    
            # now, make the data for each row
            # rows = [[center height,row height,edge offset],[etc.]]
    
            divCount = len(divs) - 1  # number of divs to check
            divCheck = 0              # current div entry
    
                RowZ = (divs[divCheck] + divs[divCheck + 1]) / 2
                RowHeight = divs[divCheck + 1] - divs[divCheck] - settings['g'] + rndc() * \
                            settings['rwhl'] * settings['gv']
                EdgeOffset = settings['eoff'] * (fmod(divCheck, 2) - 0.5) + settings['eoffv'] * rndd()
    
    
                # if row height is too shallow: delete next div entry, decrement total, and recheck current entry.
                if RowHeight < settings['hm']:
    
                    del(divs[divCheck + 1])
                    divCount -= 1  # Adjust count for removed div entry.
    
                    continue
    
                rows.append(rowOb(RowZ, RowHeight, EdgeOffset))
    
    
                divCheck += 1  # on to next div entry
    
        # set up a special opening object to handle the edges of the wall
        x = (dims['s'] + dims['e']) / 2
        z = (dims['t'] + dims['b']) / 2
    
        w = (dims['e'] - dims['s'])
        h = (dims['t'] - dims['b'])
    
        WallBoundaries = openingInvert(x, z, w, h)
    
        # Go over each row in the list, set up edge blocks and block sections
    
        for rownum in range(len(rows)):
            rowProcessing(rows[rownum], Thesketch, WallBoundaries)
    
    
        # now return the things everyone needs
        # return [rows,edgeBlocks,blockRows,Asketch]
        return [rows, Thesketch]
    
    
    
    def archGeneration(hole, vlist, flist, sideSign):
        __doc__ = """\
        Makes arches for the top and bottom, depending on sideSign
        example, Lower arch:
        archGeneration(hole, vlist, flist, -1)
        example, Upper arch:
        archGeneration(hole, vlist, flist, 1)
        hole is the opening object that the arch is for
    
        add the faces to flist
        sideSign is + or - 1, for the top or bottom arch. Other values may cause errors.
        """
    
        # working arrays for vectors and faces
        avlist = []
        aflist = []
    
        # Top (1) or bottom (-1)
        if sideSign == -1:
    
            r = hole.rl    # radius of the arch
            rt = hole.rtl  # thickness of the arch (stone height)
            v = hole.vl    # height of the arch
    
            r = hole.r     # radius of the arch
            rt = hole.rt   # thickness of the arch (stone height)
            v = hole.v     # height of the arch
    
        ra = r + rt / 2    # average radius of the arch
    
        x = hole.x
        w = hole.w
        h = hole.h
        z = hole.z
        bev = hole.b
        sideSignInv = -sideSign
    
    
        if v > w / 2:       # two arcs, to make a pointed arch
    
            zpos = z + (h / 2) * sideSign
            xoffset = r - w / 2
            # left side top, right side bottom
            # angles reference straight up, and are in radians
    
            bevHt = sqrt(bevRad ** 2 - (bevRad - (w / 2 + bev)) ** 2)
            midHalfAngle = atan(v / (r - w / 2))
            midHalfAngleBevel = atan(bevHt / (r - w / 2))
    
            bevelAngle = midHalfAngle - midHalfAngleBevel
    
            anglebeg = (PI / 2) * (sideSignInv)
            angleend = (PI / 2) * (sideSignInv) + midHalfAngle
    
            avlist, aflist = arch(ra, rt, (xoffset) * (sideSign), zpos, anglebeg, angleend, bev, bevelAngle, len(vlist))
    
            for i, vert in enumerate(avlist):
                avlist[i] = [vert[0] + hole.x, vert[1], vert[2]]
    
            # right side top, left side bottom
    
            # angles reference straight up, and are in radians
            anglebeg = (PI / 2) * (sideSign) - midHalfAngle
            angleend = (PI / 2) * (sideSign)
    
            avlist, aflist = arch(ra, rt, (xoffset) * (sideSignInv), zpos, anglebeg, angleend, bev, bevelAngle, len(vlist))
    
            for i, vert in enumerate(avlist):
                avlist[i] = [vert[0] + hole.x, vert[1], vert[2]]
    
            # keystone
            Dpth = settings['d'] + rndc() * settings['dv']
            Grout = settings['g'] + rndc() * settings['gv']
            angleBevel = (PI / 2) * (sideSign) - midHalfAngle
            Wdth = (rt - Grout - bev) * 2 * sin(angleBevel) * sideSign  # note, sin may be negative
            MidZ = ((sideSign) * (bevHt + h / 2.0) + z) + (rt - Grout - bev) \
                    * cos(angleBevel)  # note, cos may come out negative
            nearCorner = sideSign * (MidZ - z) - v - h / 2
    
    
            if sideSign == 1:
                TopHt = hole.top() - MidZ - Grout
                BtmHt = nearCorner
            else:
    
                BtmHt = - (hole.btm() - MidZ) - Grout
    
            # set the amount to bevel the keystone
    
            keystoneBevel = (bevHt - v) * sideSign
    
                avlist, aflist = MakeAKeystone(x, Wdth, MidZ, TopHt, BtmHt, Dpth, keystoneBevel, len(vlist))
    
                    for i, vert in enumerate(avlist):
                        if slope:
                            r1 = dims['t'] * sin(vert[2] * PI / (dims['t'] * 2))
                        else:
                            r1 = vert[2]
                        avlist[i] = [((vert[0] - hole.x) / r1) + hole.x, vert[1], vert[2]]
    
            # remove "debug note" once bevel is finalized.
            else:
    
                debug_prints(func="archGeneration",
                             text="Keystone was too narrow - " + str(Wdth))
    
        else:  # only one arc - curve not peak.
            # bottom (sideSign -1) arch has poorly sized blocks...
    
            zpos = z + (sideSign * (h / 2 + v - r))  # single arc positioning
    
            # angles reference straight up, and are in radians
            if sideSign == -1:
                angleOffset = PI
            else:
                angleOffset = 0.0
    
            if v < w / 2:
                halfangle = atan(w / (2 * (r - v)))
    
    
                anglebeg = angleOffset - halfangle
                angleend = angleOffset + halfangle
            else:
    
                anglebeg = angleOffset - PI / 2
                angleend = angleOffset + PI / 2
    
            avlist, aflist = arch(ra, rt, 0, zpos, anglebeg, angleend, bev, 0.0, len(vlist))
    
            for i, vert in enumerate(avlist):
                avlist[i] = [vert[0] + x, vert[1], vert[2]]
    
            # Make the Side Stones
            grt = (settings['g'] + rndc() * settings['gv'])
            width = sqrt(rt ** 2 - c ** 2) - grt
    
    
            if c > settings['hm'] + grt and c < width + grt:
    
                if radialized:
                    subdivision = settings['sdv'] * (zpos + (h / 2) * sideSign)
                else:
                    subdivision = settings['sdv']
    
                # set the height of the block, it should be as high as the max corner position, minus grout
                height = c - grt * (0.5 + c / (width + grt))
    
                # the vertical offset for the short side of the block
    
                voff = sideSign * (settings['hm'] - height)
    
                xstart = w / 2
                zstart = z + sideSign * (h / 2 + grt / 2)
                woffset = width * (settings['hm'] + grt / 2) / (c - grt / 2)
                depth = rndd() * settings['dv'] + settings['d']
    
                    offsets = [[0] * 3] * 6 + [[0] * 2 + [voff]] * 2
                    topSide = zstart + height
    
                    offsets = [[0] * 3] * 4 + [[0] * 2 + [voff]] * 2 + [[0] * 3] * 2
    
                    btmSide = zstart - height
    
                # Do some stuff to incorporate bev here
                bevelBlockOffsets(offsets, bev, -1)
    
    
                avlist, aflist = MakeABlock(
                                        [x - xstart - width, x - xstart - woffset, btmSide, topSide,
                                        -depth / 2, depth / 2], subdivision, len(vlist),
                                        Offsets=offsets, xBevScl=1
                                        )
    
                # top didn't use radialized in prev version;
                # just noting for clarity - may need to revise for "sideSign == 1"
    
                    for i, vert in enumerate(avlist):
                        avlist[i] = [((vert[0] - x) / vert[2]) + x, vert[1], vert[2]]
    
                # keep sizing same - neat arches = master masons :)
                #           grt = (settings['g'] + rndc()*settings['gv'])
                #           height = c - grt*(0.5 + c/(width + grt))
                # if grout varies may as well change width too... width = sqrt(rt**2 - c**2) - grt
                #           voff = sideSign * (settings['hm'] - height)
                #           woffset = width*(settings['hm'] + grt/2)/(c - grt/2)
    
                    offsets = [[0] * 3] * 2 + [[0] * 2 + [voff]] * 2 + [[0] * 3] * 4
                    topSide = zstart + height
    
                    offsets = [[0] * 2 + [voff]] * 2 + [[0] * 3] * 6
    
                    btmSide = zstart - height
    
                # Do some stuff to incorporate bev here
                bevelBlockOffsets(offsets, bev, 1)
    
    
                avlist, aflist = MakeABlock(
                                        [x + xstart + woffset, x + xstart + width, btmSide, topSide,
                                        -depth / 2, depth / 2], subdivision, len(vlist),
                                        Offsets=offsets, xBevScl=1
                                        )
    
                # top didn't use radialized in prev version;
                # just noting for clarity - may need to revise for "sideSign == 1"
    
                    for i, vert in enumerate(avlist):
                        avlist[i] = [((vert[0] - x) / vert[2]) + x, vert[1], vert[2]]
    
    
                vlist += avlist
                flist += aflist
        return None
    
    
    def build(Aplan):
        __doc__ = """\
        Build creates the geometry for the wall, based on the
        "Aplan" object from the "plan" function.  If physics is
        enabled, then it make a number of individual blocks with
        physics interaction enabled.  Otherwise it creates
        geometry for the blocks, arches, etc. of the wall.
        """
        vlist = []
        flist = []
        rows = Aplan[0]
    
        # all the edge blocks, redacted
    
        # AllBlocks = [[x, z, w, h, d, [corner offset matrix]], [etc.]]
    
        # loop through each row, adding the normal old blocks
        for rowidx in range(len(rows)):
    
            rows[rowidx].FillBlocks()
    
        AllBlocks = []
    
        #  If the wall is set to merge blocks, check all the blocks to see if you can merge any
    
        # seems to only merge vertical, should do horizontal too
    
            for rowidx in range(len(rows) - 1):
    
                    if slope:
                        r1 = dims['t'] * sin(abs(rows[rowidx].z) * PI / (dims['t'] * 2))
                    else:
                        r1 = abs(rows[rowidx].z)
                else:
                    r1 = 1
    
                idxThis = len(rows[rowidx].BlocksNorm[:]) - 1
    
                idxThat = len(rows[rowidx + 1].BlocksNorm[:]) - 1
    
    
                while True:
                    # end loop when either array idx wraps
    
                    if idxThis < 0 or idxThat < 0:
                        break
    
    
                    blockThis = rows[rowidx].BlocksNorm[idxThis]
    
                    blockThat = rows[rowidx + 1].BlocksNorm[idxThat]
    
                    # seems to only merge vertical, should do horizontal too...
    
                    cx, cz, cw, ch, cd = blockThis[:5]
                    ox, oz, ow, oh, od = blockThat[:5]
    
    
                    if (abs(cw - ow) < Tolerance) and (abs(cx - ox) < Tolerance):
    
                        if cw > ow:
                            BlockW = ow
                        else:
                            BlockW = cw
    
                        AllBlocks.append([(cx + ox) / 2, (cz + oz + (oh - ch) / 2) / 2,
                                         BlockW, abs(cz - oz) + (ch + oh) / 2, (cd + od) / 2, None])
    
                        rows[rowidx + 1].BlocksNorm.pop(idxThat)
    
                    elif cx > ox:
                        idxThis -= 1
                    else:
                        idxThat -= 1
    
    
        # Add blocks to create a "shelf/platform".
        # Does not account for openings (crosses gaps - which is a good thing)
        if shelfExt:
    
            SetGrtOff = settings['g'] / 2  # half grout for block size modifier
    
    
            # Use wall block settings for shelf
            SetBW = settings['w']
            SetBWVar = settings['wv']
            SetBWMin = settings['wm']
            SetBH = settings['h']
    
            # Shelf area settings
            ShelfLft = shelfSpecs['x']
            ShelfBtm = shelfSpecs['z']
            ShelfEnd = ShelfLft + shelfSpecs['w']
            ShelfTop = ShelfBtm + shelfSpecs['h']
    
            ShelfThk = shelfSpecs['d'] * 2  # use double-depth due to offsets to position at cursor.
    
    
            # Use "corners" to adjust position so not centered on depth.
    
            # Facing shelf, at cursor (middle of wall blocks)
            # - this way no gaps between platform and wall face due to wall block depth.
            wallDepth = settings['d'] / 2  # offset by wall depth so step depth matches UI setting :)
            if shelfBack:  # place blocks on backside of wall
    
                ShelfOffsets = [
                        [0, ShelfThk / 2, 0], [0, wallDepth, 0],
                        [0, ShelfThk / 2, 0], [0, wallDepth, 0],
                        [0, ShelfThk / 2, 0], [0, wallDepth, 0],
                        [0, ShelfThk / 2, 0], [0, wallDepth, 0]
                        ]
    
                ShelfOffsets = [
                        [0, -wallDepth, 0], [0, -ShelfThk / 2, 0],
                        [0, -wallDepth, 0], [0, -ShelfThk / 2, 0],
                        [0, -wallDepth, 0], [0, -ShelfThk / 2, 0],
                        [0, -wallDepth, 0], [0, -ShelfThk / 2, 0]
                        ]
    
    
        # Add blocks for each "shelf row" in area
            while ShelfBtm < ShelfTop:
    
                # Make blocks for each row - based on rowOb::fillblocks
                # Does not vary grout.
                divs = fill(ShelfLft, ShelfEnd, SetBW, SetBWMin, SetBWVar)
    
    
                # loop through the row divisions, adding blocks for each one
                for i in range(len(divs) - 1):
                    ThisBlockx = (divs[i] + divs[i + 1]) / 2
                    ThisBlockw = divs[i + 1] - divs[i] - SetGrtOff
    
    
                    AllBlocks.append([ThisBlockx, ShelfBtm, ThisBlockw, SetBH, ShelfThk, ShelfOffsets])
    
    
                ShelfBtm += SetBH + SetGrtOff  # moving up to next row...
    
    
        # Add blocks to create "steps".
        # Does not account for openings (crosses gaps - which is a good thing)
        if stepMod:
    
            SetGrtOff = settings['g'] / 2  # half grout for block size modifier
    
    
            # Vary block width by wall block variations.
            SetWidVar = settings['wv']
            SetWidMin = settings['wm']
    
    
            StepXMod = stepSpecs['t']  # width of step/tread, also sets basic block size.
    
            StepZMod = stepSpecs['v']
    
            StepLft = stepSpecs['x']
            StepRt = stepSpecs['x'] + stepSpecs['w']
    
            StepBtm = stepSpecs['z'] + StepZMod / 2  # Start offset for centered blocks
    
            StepWide = stepSpecs['w']
            StepTop = StepBtm + stepSpecs['h']
    
            StepThk = stepSpecs['d'] * 2  # use double-depth due to offsets to position at cursor.
    
    
            # Use "corners" to adjust steps so not centered on depth.
    
            # Facing steps, at cursor (middle of wall blocks)
            # - this way no gaps between steps and wall face due to wall block depth.
    
            # Also, will work fine as stand-alone if not used with wall (try block depth 0 and see what happens).
    
            wallDepth = settings['d'] / 2
            if stepBack:  # place blocks on backside of wall
    
                StepOffsets = [
                        [0, StepThk / 2, 0], [0, wallDepth, 0],
                        [0, StepThk / 2, 0], [0, wallDepth, 0],
                        [0, StepThk / 2, 0], [0, wallDepth, 0],
                        [0, StepThk / 2, 0], [0, wallDepth, 0]
                        ]
    
                StepOffsets = [
                        [0, -wallDepth, 0], [0, -StepThk / 2, 0],
                        [0, -wallDepth, 0], [0, -StepThk / 2, 0],
                        [0, -wallDepth, 0], [0, -StepThk / 2, 0],
                        [0, -wallDepth, 0], [0, -StepThk / 2, 0]
                        ]
    
    
        # Add steps for each "step row" in area (neg width is interesting but prevented)
            while StepBtm < StepTop and StepWide > 0:
    
                # Make blocks for each step row - based on rowOb::fillblocks
                # Does not vary grout.
    
    
                if stepOnly:  # "cantilevered steps"
    
                    if stepLeft:
                        stepStart = StepRt - StepXMod
                    else:
                        stepStart = StepLft
    
                    AllBlocks.append([stepStart, StepBtm, StepXMod, StepZMod, StepThk, StepOffsets])
                else:
                    divs = fill(StepLft, StepRt, StepXMod, SetWidMin, SetWidVar)
    
    
                    # loop through the row divisions, adding blocks for each one
                    for i in range(len(divs) - 1):
                        ThisBlockx = (divs[i] + divs[i + 1]) / 2
                        ThisBlockw = divs[i + 1] - divs[i] - SetGrtOff
    
    
                        AllBlocks.append([ThisBlockx, StepBtm, ThisBlockw, StepZMod, StepThk, StepOffsets])
    
    
                StepBtm += StepZMod + SetGrtOff  # moving up to next row...
                StepWide -= StepXMod             # reduce step width
    
    
                # adjust side limit depending on direction of steps
                if stepLeft:
    
                    StepRt -= StepXMod   # move in from right
    
                    StepLft += StepXMod  # move in from left
    
        # Copy all the blocks out of the rows
    
        for row in rows:
            AllBlocks += row.BlocksEdge
            AllBlocks += row.BlocksNorm
    
    
        # This loop makes individual blocks for each block specified in the plan
    
            x, z, w, h, d, corners = block
    
                if slope:
                    r1 = dims['t'] * sin(z * PI / (dims['t'] * 2))
                else:
                    r1 = z
            else:
                r1 = 1
    
            geom = MakeABlock([x - w / 2, x + w / 2, z - h / 2, z + h / 2, -d / 2, d / 2],
                              settings['sdv'], len(vlist),
    
                              corners, None, settings['b'] + rndd() * settings['bv'], r1)
    
            vlist += geom[0]
            flist += geom[1]
    
        # This loop makes Arches for every opening specified in the plan.
        for hole in Aplan[1]:
            # lower arch stones
    
            if hole.vl > 0 and hole.rtl > (settings['g'] + settings['hm']):  # make lower arch blocks
    
            # top arch stones
            if hole.v > 0 and hole.rt > (settings['g'] + settings['hm']):    # make upper arch blocks
    
        # Warp all the points for domed stonework
    
            for i, vert in enumerate(vlist):
                vlist[i] = [vert[0], (dims['t'] + vert[1]) * cos(vert[2] * PI / (2 * dims['t'])),
                            (dims['t'] + vert[1]) * sin(vert[2] * PI / (2 * dims['t']))]
    
        # Warp all the points for radial stonework
    
            for i, vert in enumerate(vlist):
                vlist[i] = [vert[2] * cos(vert[0]), vert[2] * sin(vert[0]), vert[1]]
    
    # The main function
    
    def createWall(radial, curve, openings, mergeBlox, shelf, shelfSide,
            steps, stepDir, stepBare, stepSide):
        __doc__ = """\
    
        Call all the functions you need to make a wall, return the verts and faces.
    
        """
        global radialized
        global slope
        global openingSpecs
        global bigBlock
        global shelfExt
        global stepMod
        global stepLeft
        global shelfBack
        global stepOnly
        global stepBack
    
        # set all the working variables from passed parameters
    
        radialized = radial
        slope = curve
        openingSpecs = openings
        bigBlock = mergeBlox
        shelfExt = shelf
        stepMod = steps
        stepLeft = stepDir
        shelfBack = shelfSide
        stepOnly = stepBare
        stepBack = stepSide
    
        asketch = sketch()
        aplan = plan(asketch, 0)
    
        return build(aplan)