Skip to content
Snippets Groups Projects
Castle.py 140 KiB
Newer Older
  • Learn to ignore specific revisions
  •     DepthFront = SetDepth / 2 + rndc() * SetDepthVar
    
    
        # there's something wrong here...
    
        if wallDome:
            subdivision = settings['sdv']
        else:
            subdivision = 0.12
    
        blockGap = SetGrt / (2 * ra)  # grout offset
        # set up the offsets, it will be the same for every block
        offsets = ([[0] * 2 + [bevel]] + [[0] * 3] * 3) * 2
    
        # make the divisions in the "length" of the arch
        divs = fill(archStart, archEnd, settings['w'] / ra, settings['w'] / ra, settings['wv'] / ra)
    
        for i in range(len(divs) - 1):
             # modify block offsets for bevel.
            if i == 0:
                ThisOffset = offsets[:]
                pointsToAffect = (0, 2, 3)
    
                for num in pointsToAffect:
                    offsets[num] = ThisOffset[num][:]
                    offsets[num][0] += bevAngle
            elif i == len(divs) - 2:
                ThisOffset = offsets[:]
                pointsToAffect = (4, 6, 7)
    
                for num in pointsToAffect:
                    offsets[num] = ThisOffset[num][:]
                    offsets[num][0] -= bevAngle
            else:
                ThisOffset = offsets
    
            geom = MakeABlock([divs[i] + blockGap, divs[i + 1] - blockGap, ArchInner, ArchOuter, DepthBack, DepthFront],
                              subdivision, len(avlist) + vll, ThisOffset, [])
    
            avlist += geom[0]
            aflist += geom[1]
    
            if SetDepthVar:  # vary depth
                DepthBack = -SetDepth / 2 - rndc() * SetDepthVar
                DepthFront = SetDepth / 2 + rndc() * SetDepthVar
    
        for i, vert in enumerate(avlist):
            v0 = vert[2] * sin(vert[0]) + x
            v1 = vert[1]
            v2 = vert[2] * cos(vert[0]) + z
    
            if wallDome:
                r1 = wallTopZ * (sin(v2 * cPie / (wallTopZ * 2)))
    
            #            if settings['Slope']: r1 = wallTopZ*(sin(v2*cPie/(wallTopZ*2)))
            #            else: r1 = v2 # disc
    
                v0 = v0 / r1
    
            avlist[i] = [v0, v1, v2]
    
        return (avlist, aflist)
    
    
    #################################################################
    #
    # Make wedge blocks for openings.
    #
    #  examples:
    #   wedgeBlocks(row, LeftWedgeEdge, LNerEdge, LEB, r1)
    #   wedgeBlocks(row, RNerEdge, RightWedgeEdge, rSide, r1)
    #
    def wedgeBlocks(row, opening, leftPos, rightPos, edgeSide, r1):
    
        wedgeWRad = settings['w'] / r1
    
        wedgeEdges = fill(leftPos, rightPos, wedgeWRad, wedgeWRad, settings['wv'] / r1)
    
        blockDepth = settings['d']
        blockDepthV = settings['dv']
        blockGap = settings['g'] / r1
    
        for i in range(len(wedgeEdges) - 1):
            x = (wedgeEdges[i + 1] + wedgeEdges[i]) / 2
            w = wedgeEdges[i + 1] - wedgeEdges[i] - blockGap
            halfBW = w / 2
    
            ThisBlockDepth = blockDepth + rndd() * blockDepthV
    
            LVert = -((row.z - ((row.h / 2) * edgeSide)) - opening.edgeV(x - halfBW, edgeSide))
    
            #        LVert =  -( row.z - (row.h/2)*edgeSide - (opening.edgeV(x-halfBW,edgeSide)))
    
            RightVertOffset = -(row.z - (row.h / 2) * edgeSide - opening.edgeV(x + halfBW, edgeSide))
    
            # Wedges are on top = Voff, blank, Voff, blank
            # Wedges are on btm = blank, Voff, blank, Voff
            ThisBlockOffsets = [[0, 0, LVert]] * 2 + [[0] * 3] * 2 + [[0, 0, RightVertOffset]] * 2
            # Instert or append "blank" for top or bottom wedges.
            if edgeSide == 1:
                ThisBlockOffsets = ThisBlockOffsets + [[0] * 3] * 2
            else:
                ThisBlockOffsets = [[0] * 3] * 2 + ThisBlockOffsets
    
            row.BlocksEdge.append([x, row.z, w, row.h, ThisBlockDepth, ThisBlockOffsets])
    
    
    ############################################################
    #
    #
        # set end blocks
        # check for openings, record top and bottom of row for right and left of each
        # if both top and bottom intersect create blocks on each edge, appropriate to the size of the overlap
        # if only one side intersects, run fill to get edge positions, but this should never happen
        #
    #
    def rowProcessing(row, holeList, WallBoundaries):
    
        if settings['Radial']:  # radial stonework sets the row radius
            if settings['Slope']:
                r1 = abs(dims['t'] * sin(row.z * cPie / (dims['t'] * 2)))
            else:
                r1 = abs(row.z)
        else:
            r1 = 1
    
        # set block working values
        blockWidth = settings['w']
        blockWVar = settings['wv']
        blockDepth = settings['d']
        blockDVar = settings['dv']
    
        blockGap = settings['g'] / r1
        blockHMin = BLOCK_MIN + blockGap
    
        # set row working values
        rowH = row.h
        rowH2 = rowH / 2
        rowEdge = row.rowEdge / r1
        rowStart = dims['s'] + rowEdge
    
        # shouldn't rowEnd be minus rowEdge?
    
        rowEnd = dims['e'] + rowEdge
        rowTop = row.z + rowH2
        rowBtm = row.z - rowH2
    
        # left and right wall limits for top and bottom of row.
        edgetop = [[rowStart, WallBoundaries], [rowEnd, WallBoundaries]]
        edgebtm = [[rowStart, WallBoundaries], [rowEnd, WallBoundaries]]
    
        for hole in holeList:
            # check the top and bottom of the row, looking at the opening from the right
            holeEdge = [hole.edgeS(rowTop, -1), hole.edgeS(rowBtm, -1)]
    
            # If either one hit the opening, make split points for the side of the opening.
            if holeEdge[0] or holeEdge[1]:
                holeEdge += [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(holeEdge):
                    if pos == None:
                        holeEdge[i] = hole.x
    
                # add the intersects to the list of edge points
                edgetop.append([holeEdge[0], hole])
                edgetop.append([holeEdge[2], hole])
                edgebtm.append([holeEdge[1], hole])
                edgebtm.append([holeEdge[3], hole])
    
        # make the walls in order, sort the intersects.
    
        #  remove edge points that are out of order;
        #  else the "oddity" where opening overlap creates blocks inversely.
    
        edgetop.sort()
        edgebtm.sort()
    
        # These two loops trim the edges to the limits of the wall.
        # This way openings extending outside the wall don't enlarge the wall.
        while True:
            try:
                if (edgetop[-1][0] > rowEnd) or (edgebtm[-1][0] > rowEnd):
                    edgetop[-2:] = []
                    edgebtm[-2:] = []
                else:
                    break
            except IndexError:
                break
        # still trimming the edges...
        while True:
            try:
                if (edgetop[0][0] < rowStart) or (edgebtm[0][0] < rowStart):
                    edgetop[:2] = []
                    edgebtm[:2] = []
                else:
                    break
            except IndexError:
                break
    
        # finally, make edge blocks and rows!
    
        # Process each section, a pair of points in edgetop,
        # and place the edge blocks and inbetween normal block zones into the row object.
    
        # maximum distance to span with one block
        MaxWid = (blockWidth + blockWVar) / r1
    
        for OpnSplitNo in range(int(len(edgetop) / 2)):
            lEdgeIndx = 2 * OpnSplitNo
            rEdgeIndx = lEdgeIndx + 1
    
            leftOpening = edgetop[lEdgeIndx][1]
            rightOpening = edgetop[rEdgeIndx][1]
    
            # find the difference between the edge top and bottom on both sides
            LTop = edgetop[lEdgeIndx][0]
            LBtm = edgebtm[lEdgeIndx][0]
            RTop = edgetop[rEdgeIndx][0]
            RBtm = edgebtm[rEdgeIndx][0]
            LDiff = LBtm - LTop
            RDiff = RTop - RBtm
    
            # set side edge limits from top and bottom
            if LDiff > 0:  # if furthest edge is top,
                LEB = 1
                LFarEdge = LTop  # The furthest edge
                LNerEdge = LBtm  # the nearer edge
            else:  # furthest edge is bottom
                LEB = -1
                LFarEdge = LBtm
                LNerEdge = LTop
    
            if RDiff > 0:  # if furthest edge is top,
                rSide = 1
                RFarEdge = RTop  # The furthest edge
                RNerEdge = RBtm  # the nearer edge
            else:  # furthest edge is bottom
                rSide = -1
                RFarEdge = RBtm  # The furthest edge
                RNerEdge = RTop  # the nearer edge
    
            blockXx = RNerEdge - LNerEdge  # The space between the closest edges of the openings in this section of the row
            blockXm = (RNerEdge + LNerEdge) / 2  # The mid point between the nearest edges
    
            # check the left and right sides for wedge blocks
            # find the edge of the correct side, offset for minimum block height.  The LEB decides top or bottom
            ZPositionCheck = row.z + (rowH2 - blockHMin) * LEB
    
            # edgeS may return "None"
    
            LeftWedgeEdge = leftOpening.edgeS(ZPositionCheck, 1)
    
            if (abs(LDiff) > blockWidth) 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.
            ZPositionCheck = row.z + (rowH2 - blockHMin) * rSide
    
            # edgeS may return "None"
    
            RightWedgeEdge = rightOpening.edgeS(ZPositionCheck, -1)
            if (abs(RDiff) > blockWidth) or (not RightWedgeEdge):
                # make wedge blocks
                if not RightWedgeEdge:
                    RightWedgeEdge = rightOpening.x
                wedgeBlocks(row, rightOpening, RNerEdge, RightWedgeEdge, rSide, 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
    
            # Single block - needed for arch "point" (keystone).
            if blockXx < MaxWid:
                x = (LNerEdge + RNerEdge) / 2.
                w = blockXx
                ThisBlockDepth = rndd() * blockDVar + blockDepth
                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
    
                pointsToAffect = (0, 2)
                bevelBlockOffsets(ThisBlockOffsets, leftOpening.edgeBev(rowTop), pointsToAffect)
    
                pointsToAffect = (4, 6)
                bevelBlockOffsets(ThisBlockOffsets, -rightOpening.edgeBev(rowTop), pointsToAffect)
    
                row.BlocksEdge.append([x, row.z, w, rowH, ThisBlockDepth, ThisBlockOffsets])
                continue
    
            # must be two or more blocks
    
            # Left offsets
            BtmOff = LBtm - LNerEdge
            TopOff = LTop - LNerEdge
            leftOffsets = [[BtmOff, 0, 0]] * 2 + [[TopOff, 0, 0]] * 2 + [[0] * 3] * 4
            bevelL = leftOpening.edgeBev(rowTop)
    
            pointsToAffect = (0, 2)
            bevelBlockOffsets(leftOffsets, bevelL, pointsToAffect)
    
            # Right offsets
            BtmOff = RBtm - RNerEdge
            TopOff = RTop - RNerEdge
            rightOffsets = [[0] * 3] * 4 + [[BtmOff, 0, 0]] * 2 + [[TopOff, 0, 0]] * 2
            bevelR = rightOpening.edgeBev(rowTop)
    
            pointsToAffect = (4, 6)
            bevelBlockOffsets(rightOffsets, -bevelR, pointsToAffect)
    
            if blockXx < MaxWid * 2:  # only two blocks?
                # div is the x position of the dividing point between the two bricks
                div = blockXm + (rndd() * blockWVar) / r1
    
                # set the x position and width for the left block
                x = (div + LNerEdge) / 2 - blockGap / 4
                w = (div - LNerEdge) - blockGap / 2
                ThisBlockDepth = rndd() * blockDVar + blockDepth
                # For reference: EdgeBlocks = [[x,z,w,h,d,[corner offset matrix]],[etc.]]
                row.BlocksEdge.append([x, row.z, w, rowH, ThisBlockDepth, leftOffsets])
    
                # Initialize for the block on the right side
                x = (div + RNerEdge) / 2 + blockGap / 4
                w = (RNerEdge - div) - blockGap / 2
                ThisBlockDepth = rndd() * blockDVar + blockDepth
                row.BlocksEdge.append([x, row.z, w, rowH, ThisBlockDepth, rightOffsets])
                continue
    
            # more than two blocks in the row, and no wedge blocks
    
            # make Left edge block
            # set the x position and width for the block
            widOptions = [blockWidth, bevelL + blockWidth, leftOpening.ts]
            baseWidMax = max(widOptions)
            w = baseWidMax + row.rowEdge + (rndd() * blockWVar)
            widOptions[0] = blockWidth
            widOptions[2] = w
            w = max(widOptions) / r1 - blockGap
            x = w / 2 + LNerEdge + blockGap / 2
            BlockRowL = x + w / 2
            ThisBlockDepth = rndd() * blockDVar + blockDepth
            row.BlocksEdge.append([x, row.z, w, rowH, ThisBlockDepth, leftOffsets])
    
            # make Right edge block
            # set the x position and width for the block
            widOptions = [blockWidth, bevelR + blockWidth, rightOpening.ts]
            baseWidMax = max(widOptions)
            w = baseWidMax + row.rowEdge + (rndd() * blockWVar)
            widOptions[0] = blockWidth
            widOptions[2] = w
            w = max(widOptions) / r1 - blockGap
            x = RNerEdge - w / 2 - blockGap / 2
            BlockRowR = x - w / 2
            ThisBlockDepth = rndd() * blockDVar + blockDepth
            row.BlocksEdge.append([x, row.z, w, rowH, ThisBlockDepth, rightOffsets])
    
            row.RowSegments.append([BlockRowL, BlockRowR])
    
    
    #####################################
    #
    # Makes arches for the top and bottom
    # hole is the "wall opening" that the arch is for.
    #
    def archGeneration(hole, vlist, flist, sideSign):
    
        avlist = []
        aflist = []
    
        if sideSign == 1:  # top
            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
        else:  # bottom
            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
    
        ra = r + rt / 2  # average radius of the arch
        x = hole.x
        w = hole.w
        holeW2 = w / 2
        h = hole.h
        z = hole.z
        bev = hole.b
    
        blockGap = settings['g']
        blockHMin = BLOCK_MIN + blockGap
    
        blockDepth = settings['d']
        blockDVar = settings['dv']
    
        if v > holeW2:  # two arcs, to make a pointed arch
            # positioning
            zpos = z + (h / 2) * sideSign
            xoffset = r - holeW2
            # left side top, right side bottom
            # angles reference straight up, and are in radians
            bevRad = r + bev
            bevHt = sqrt(bevRad**2 - (bevRad - (holeW2 + bev))**2)
            midHalfAngle = atan(v / (r - holeW2))
            midHalfAngleBevel = atan(bevHt / (r - holeW2))
            bevelAngle = midHalfAngle - midHalfAngleBevel
            anglebeg = (cPieHlf) * (-sideSign)
            angleend = (cPieHlf) * (-sideSign) + 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 = (cPieHlf) * (sideSign) - midHalfAngle
            angleend = (cPieHlf) * (sideSign)
    
            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
    
            # keystone
            Dpth = blockDepth + rndc() * blockDVar
            angleBevel = (cPieHlf) * (sideSign) - midHalfAngle
            Wdth = (rt - blockGap - bev) * 2 * sin(angleBevel) * sideSign  # note, sin may be negative
            MidZ = ((sideSign) * (bevHt + h / 2.0) + z) + (rt - blockGap - bev) * cos(angleBevel)  # note, cos may come out negative too
            nearCorner = sideSign * (MidZ - z) - v - h / 2
    
            if sideSign == 1:
                TopHt = hole.top() - MidZ - blockGap
                BtmHt = nearCorner
            else:
                BtmHt = - (hole.btm() - MidZ) - blockGap
                TopHt = nearCorner
    
            # set the amout to bevel the keystone
            keystoneBevel = (bevHt - v) * sideSign
            if Wdth >= blockHMin:
                avlist, aflist = MakeAKeystone(x, Wdth, MidZ, TopHt, BtmHt, Dpth, keystoneBevel, len(vlist))
    
                if settings['Radial']:
                    for i, vert in enumerate(avlist):
                        if settings['Slope']:
                            r1 = dims['t'] * sin(vert[2] * cPie / (dims['t'] * 2))
                        else:
                            r1 = vert[2]
                        avlist[i] = [((vert[0] - hole.x) / r1) + hole.x, vert[1], vert[2]]
    
                vlist += avlist
                flist += aflist
    
        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 = cPie
            else:
                angleOffset = 0.0
    
            if v < holeW2:
                halfangle = atan(w / (2 * (r - v)))
    
                anglebeg = angleOffset - halfangle
                angleend = angleOffset + halfangle
            else:
                anglebeg = angleOffset - cPieHlf
                angleend = angleOffset + cPieHlf
    
            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
            archBW = sqrt(rt**2 - c**2)
            archBWG = archBW - blockGap
    
            if c > blockHMin and c < archBW:
                subdivision = settings['sdv']
                if settings['Radial']:
                    subdivision *= (zpos + (h / 2) * sideSign)
    
                # set the height of the block, it should be as high as the max corner position, minus grout
                height = c - blockGap * (0.5 + c / archBW)
    
                # the vertical offset for the short side of the block
                voff = sideSign * (blockHMin - height)
                xstart = holeW2
                zstart = z + sideSign * (h / 2 + blockGap / 2)
                woffset = archBWG * (blockHMin) / (c - blockGap / 2)
    
                #            woffset = archBWG*(BLOCK_MIN + blockGap/2)/(c - blockGap/2)
    
                depth = blockDepth + (rndd() * blockDVar)
    
                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
    
                pointsToAffect = (4, 6)  # left
                bevelBlockOffsets(offsets, bev, pointsToAffect)
    
                avlist, aflist = MakeABlock([x - xstart - archBWG, x - xstart - woffset, btmSide, topSide, -depth / 2, depth / 2], subdivision, len(vlist), Offsets=offsets)
    
    
                # top didn't use radialized in prev version; just noting for clarity - may need to revise for "sideSign == 1"
    
                if settings['Radial']:
                    for i, vert in enumerate(avlist):
                        avlist[i] = [((vert[0] - x) / vert[2]) + x, vert[1], vert[2]]
    
                vlist += avlist
                flist += aflist
    
                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
    
                pointsToAffect = (0, 2)  # right
                bevelBlockOffsets(offsets, bev, pointsToAffect)
    
                avlist, aflist = MakeABlock([x + xstart + woffset, x + xstart + archBWG, btmSide, topSide, -depth / 2, depth / 2], subdivision, len(vlist), Offsets=offsets)
    
    
                # top didn't use radialized in prev version; just noting for clarity - may need to revise for "sideSign == 1"
    
                if settings['Radial']:
                    for i, vert in enumerate(avlist):
                        avlist[i] = [((vert[0] - x) / vert[2]) + x, vert[1], vert[2]]
    
                vlist += avlist
                flist += aflist