Skip to content
Snippets Groups Projects
Blocks.py 64.6 KiB
Newer Older
  • Learn to ignore specific revisions
  •         InnerMid = (RNerEdge + LNerEdge)/2
    
            #maximum distance to span with one block
            MaxWid = (settings['w']+settings['wv'])/r1
            AveWid = settings['w']
            MinWid = settings['wm']
    
            #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
                LFarEdge , LTop , LBtm = LNerEdge, LNerEdge, LNerEdge
                LDiff = 0
    
            #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
                RFarEdge , RTop , RBtm = RNerEdge, RNerEdge, RNerEdge
                RDiff = 0
    
            #Check to see if the edges are close enough toegther to warrant a single block filling it
            if (InnerDiff < MaxWid):
                #if this is true, then this row is just one block!
                x = (LNerEdge + RNerEdge)/2.
                w = InnerDiff
                ThisBlockDepth = rndd()*settings['dv']+settings['d']
                BtmOff = LBtm - LNerEdge
                TopOff = LTop - LNerEdge
    
    Campbell Barton's avatar
    Campbell Barton committed
                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
    
    Campbell Barton's avatar
    Campbell Barton committed
    
    
            # 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
    
    Campbell Barton's avatar
    Campbell Barton committed
                div = InnerMid + (rndd()*settings['wv'])/r1
    
                #set the grout distance, since we need grout seperation 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])
                continue
    
            #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])
        return None
    
    
    def plan(Thesketch, oldrows = 0):
        __doc__ = """\
    
    Campbell Barton's avatar
    Campbell Barton committed
        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.
    
    Campbell Barton's avatar
    Campbell Barton committed
        if oldrows: rows = oldrows
    
        else:
            #rows holds the important information common to all rows
            #rows = [list of row objects]
            rows = []
    
            #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'])
            splits.sort()
    
            #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])
                    #(settings['hm']+settings['g']) is the old minimum value
                    if diff < (settings['h']-settings['hv']+settings['g']):
                        del(divs[i])
                        break
    
            #now merge the divs and splits lists
            divs += splits
    
            #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'])
    
            divs.sort()
    
            #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
    
            while divCheck < divCount:
                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 = OpeningInv(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__ = """\
    
    Campbell Barton's avatar
    Campbell Barton committed
        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 verticies to vlist
        add the faces to flist
        sideSign is + or - 1, for the top or bottom arch. Other values may cause errors.
    
    Campbell Barton's avatar
    Campbell Barton committed
        """
    
    
        # 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
            c = hole.cl
        else:
            r = hole.r #radius of the arch
            rt = hole.rt #thickness of the arch (stone height)
            v = hole.v #height of the arch
            c = hole.c
    
        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
            # positioning
            zpos = z + (h/2)*sideSign
            xoffset = r - w/2
            #left side top, right side bottom
            #angles reference straight up, and are in radians
            bevRad = r + bev
            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]]
            vlist += avlist
            flist += aflist
    
            #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]]
    
            vlist += avlist
            flist += aflist
    
            #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 too
            nearCorner = sideSign*(MidZ - z) - v - h/2
    
            if sideSign == 1:
                TopHt = hole.top() - MidZ - Grout
                BtmHt = nearCorner
            else:
                BtmHt =  - (hole.btm() - MidZ) - Grout
                TopHt = nearCorner
    
            # set the amout to bevel the keystone
            keystoneBevel = (bevHt - v)*sideSign
            if Wdth >= settings['hm']:
                avlist,aflist = MakeAKeystone(x, Wdth, MidZ, TopHt, BtmHt, Dpth, keystoneBevel, len(vlist))
    
                if radialized:
                    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]]
    
                vlist += avlist
                flist += aflist
    # remove "debug note" once bevel is finalized.
            else: print("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]]
    
            vlist += avlist
            flist += aflist
    
            #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']
    
                if sideSign == 1:
                    offsets = [[0]*3]*6 + [[0]*2 + [voff]]*2
                    topSide = zstart+height
                    btmSide = zstart
                else:
                    offsets = [[0]*3]*4 + [[0]*2 + [voff]]*2 + [[0]*3]*2
                    topSide = zstart
                    btmSide = zstart-height
                # Do some stuff to incorporate bev here
    
    Campbell Barton's avatar
    Campbell Barton committed
                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"
                if radialized:
                    for i,vert in enumerate(avlist): avlist[i] = [((vert[0]-x)/vert[2])+x,vert[1],vert[2]]
    
                vlist += avlist
                flist += aflist
    
    # keep sizing same - neat arches = master masons :)
    
    Campbell Barton's avatar
    Campbell Barton committed
    #           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
    
    Campbell Barton's avatar
    Campbell Barton committed
    #           voff = sideSign * (settings['hm'] - height)
    #           woffset = width*(settings['hm'] + grt/2)/(c - grt/2)
    
    
                if sideSign == 1:
                    offsets = [[0]*3]*2 + [[0]*2 + [voff]]*2 + [[0]*3]*4
                    topSide = zstart+height
                    btmSide = zstart
                else:
                    offsets = [[0]*2 + [voff]]*2 + [[0]*3]*6
                    topSide = zstart
                    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"
                if radialized:
                    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__ = """\
    
    Campbell Barton's avatar
    Campbell Barton committed
        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]
    
    #dead code...
        #Physics setup is horribly broken.  Revisit when new API is in place.
        '''if False: #settings['physics']:
    
    Campbell Barton's avatar
    Campbell Barton committed
            geom = MakeABlock([-0.5,0.5,-0.5,0.5,-0.5,0.5], 3, 0, None,[], 3*settings['b']/(settings['w'] + settings['h'] + settings['d']))
            blockmesh = Blender.Mesh.New('block')
            vlist += geom[0]
            flist += geom[1]
            blockmesh.verts.extend(vlist)
            blockmesh.faces.extend(flist)
    
            for block in Aplan[1]:
                x,z,w,h,d = block[:5]
                block = scn.objects.new(blockmesh, 'block')
                block.loc = [x, 0, z]
                block.size = [w,d,h]
                block.rbFlags = Blender.Object.RBFlags['BOUNDS'] | Blender.Object.RBFlags['ACTOR'] | Blender.Object.RBFlags['DYNAMIC'] | Blender.Object.RBFlags['RIGIDBODY']
                block.rbShapeBoundType = Blender.Object.RBShapes['BOX']
    
    
            for row in Aplan[2]:#row=[xstart,xend,z,h]
                #currently, radial geometry is disabled for physics blocks setup
                if radialized:
                    if slope: r1 = dims['t']*sin(row[2]*PI/(dims['t']*2))
                    else: r1 = row[2]
    
                else: r1 = 1
    
                divs = fill(row[0], row[1], settings['w'], settings['wm'], settings['wv'])
                for i in range(len(divs)-1):
                    block = scn.objects.new(blockmesh, 'block')
                    block.loc = [(divs[i]+divs[i+1])/2, 0, row[2]]
                    block.size = [(divs[i + 1] - divs[i]) - settings['g'], (settings['d'] + rndd()*settings['dv'])*(1-settings['t']*((row[3]-dims['b'])/(dims['t'] - dims['b']))), row[3]]
                    block.rbFlags = Blender.Object.RBFlags['BOUNDS'] | Blender.Object.RBFlags['ACTOR'] | Blender.Object.RBFlags['DYNAMIC'] | Blender.Object.RBFlags['RIGIDBODY']
                    block.rbShapeBoundType = Blender.Object.RBShapes['BOX']
    
            return None'''
    #end dead code...
    
    
        # 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)):#row = row object
            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
        if bigBlock:
            for rowidx in range(len(rows)-1):
                if radialized:
                    if slope: r1 = dims['t']*sin(abs(rows[rowidx].z)*PI/(dims['t']*2))
                    else: r1 = abs(rows[rowidx].z)
                else: r1 = 1
    
                Tollerance = settings['g']/r1
                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) < Tollerance) and (abs(cx - ox) < Tollerance) :
                        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].BlocksNorm.pop(idxThis)
                        rows[rowidx+1].BlocksNorm.pop(idxThat)
                        idxThis -= 1
                        idxThat -= 1
    
                    elif cx > ox: idxThis -= 1
                    else: idxThat -= 1
    
        #
    
    Campbell Barton's avatar
    Campbell Barton committed
        #
    
        # 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]]
            else:
                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]]
    
    
    Campbell Barton's avatar
    Campbell Barton committed
        # 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...
        #
    
    Campbell Barton's avatar
    Campbell Barton committed
        #
    
        # 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 # offset by wall depth so step depth matches UI setting :)
            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]]
            else:
                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]]
    
    
    Campbell Barton's avatar
    Campbell Barton committed
        # 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
                else:
                    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
        for block in AllBlocks:
            x,z,w,h,d,corners = block
            if radialized:
                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
                archGeneration(hole, vlist, flist, -1)
    
            #top arch stones
            if hole.v > 0 and hole.rt > (settings['g'] + settings['hm']):#make upper arch blocks
                archGeneration(hole, vlist, flist, 1)
        #
    
        #Warp all the points for domed stonework
        if slope:
            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
        if radialized:
            for i,vert in enumerate(vlist):
                vlist[i] = [vert[2]*cos(vert[0]),vert[2]*sin(vert[0]),vert[1]]
    
        return vlist, flist
    
    
    #The main function
    def createWall(radial, curve, openings, mergeBlox, shelf, shelfSide,
            steps, stepDir, stepBare, stepSide):
        __doc__ = """\
    
    Campbell Barton's avatar
    Campbell Barton committed
        Call all the funcitons 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)