##  Embed_Plate.py Version 1.09

##  Copyright (c) 2006 Bruce Vaughan, BV Detailing & Design, Inc.

##  All rights reserved.

##  NOT FOR SALE. The software is provided "as is" without any warranty.

############################################################################

"""

    Add embedded plates with studs for beam connections to concrete foundation or shear walls.

    Assuming the beam member WP is at the face of wall, the embed member line will be at face of wall.

    Select beam member. Enter information into dialog box.

    User must enter the proper embedded plate plan rotation.

    Studs will be applied to the plate vertical face.   

    Nailer holes can be added in the corners.

    Default embedded plate sizes and member piece marks are determined by calling function embed_plate_dims(mem)

    and are based upon the member depth.

    You must be in plan to execute this script for the intended purpose.

    The user must manually modify the member description.

    The user must modify the member views in member isolation.

 

    NOTE:

    This script will read and write the defaults to a disk file if so enabled in the "Defaults section". The first

    time the script is executed the defaults file will be created. Subsequent script executions will import the

    defaults used in the previous execution. Set the variable "enable_default_import_export" to "Disable" to disable

    this feature.

   

    Developed from V7Misc_SS_R1.py (see for additional notes)

   

    Originally developed in SDS2 7.021 1/29/06 (R1)

    Developed by Bruce Vaughan, BV Detailing & Design, Inc. (BVD)  (615) 646-9239

    For comments, suggestions or questions call BVD at the number above.

 

    Version 1.02 (1/31/06)  Incorporate mem.main_mtrl() to determine global points;

                            mem.plan_rotation and mem.translate still broken

    Version 1.03 (2/3/06)   Add path for defaults file. Go to "Variables" to modify system path.

    Version 1.04 (7/28/06)  Add code to adjust plate and stud rotations for SDS/2 Versions 7.023 and higher.

    Version 1.05 (9/12/06)  Add material usage description to plate and stud material.

    Version 1.06 (10/22/06) Enable sequence for members ***SEQUENCE DOES NOT WORK***

                            Add option to print documentation only

    Version 1.07 (3/15/07)  Read/save default files - subdirectory 'SDS/2 root data'/macro/Defaults

                            Image files - subdirectory 'SDS/2 root data'/macro/Images

    Version 1.08 (3/16/07) -    Corrected image path

    Version 1.09 (3/17/07) -    Import modules

                                Update code

    ********************************************************************************

    ****NOTE: This version is not compatible with SDS/2 versions prior to 7.023.****

    ********************************************************************************

 

    Go to "Defaults section" to modify script defaults.

"""

def run_script():

    # startup code begin

    import os

    from math import cos, pi, tan, atan2, atan, sin

    from param import yes_or_no, ResponseNotOK, Units, ClearSelection, Dialog, dim_print, Warning, dim

    from macrolib.FileDefaults import import_data, export_data

    # macrolib.pickle required

    from macrolib.angle import rtod, dtor, calc_plan_rotation

    from macrolib.stud_info import stud_dim

    from macrolib.PolarPt import polar_pt_plan

    from macrolib.MemSelection import mem_select

    # macrolib.MemCnt required

 

    Units("feet")

    from shape import Shape

    from point import Point, PointLocate

    from member import Member, MemberLocate

    from mtrl_list import MtrlLocate, HoleLocate

    from rolled_section import RolledSection

    from hole_add import Hole

    from shr_stud import ShrStud

    from job import Job

    from fab import Fabricator

    # startup code end

    ###################################################################################

    ## Variables section

    # defaults file path

    default_file_path = os.path.join(os.getcwd(), "macro", "Defaults")

    # defaults file

    def_file = "Embed_Plate.txt"

    script_name = "Embed_Plate_v1.09.py"

    # Enable or disable the importing and exporting of dialog dictionary variables "Enable" "Disable"

    enable_default_import_export = "Enable"

 

    image_path = os.path.join(os.getcwd(), "macro", "Images")

    image_name1 = os.path.join(image_path, "Embed_Plate2.gif")

    image_name2 = os.path.join(image_path, "Embed_Plate1.gif")

    image_name4 = os.path.join(image_path, "Embed_Plate4.gif")           

 

    stud_diaList = ("1/4", "3/8", "1/2", "5/8", "3/4", "7/8", "1")

    finishList = ("None", "Red Oxide", "Yellow Zinc", "Gray Oxide", "Sandblasted", "Blued Steel", "Galvanized")

 

    ## Defaults section

    # vertical embedded plate offset

    embed_vertical_offset = 3.0

    # "Left End", "Right End"

    which_end = "Left End"

    # "User" "System" Create user piece mark or system piece mark

    embed_mark_system_user = "User"             

    user_piece_mark = "XXXX"

    # Member sequence - must be a string

    plate_seq = "12"

    # stud diameter ("1/4", "3/8", "1/2", "5/8", "3/4", "7/8", "1")

    stud_diam = 0.75

    stud_length = 6.1875

    # finishList

    stud_color = "Yellow Zinc"

 

    # stud pattern offset x direction

    x_off = 0.0

    # stud pattern offset z direction

    z_off = 0.0

    # stud spacing along miscellaneous member x-axis

    x_spa = 6.0

    # stud spacing along miscellaneous member z-axis

    z_spa = 6.0

 

    # (0, 2, 4) 0 = none, 2 = opposite corners, 4 = each corner (integer)

    add_nailer_holes = 4

    # nailer hole edge distance

    nailer_edge_dist = 0.75

    # nailer hole size

    nailer_hole_size = 0.5625

    # embed rotation

    embed_plan_rotation = 0.0

 

    # material grade Job().steel_grades("Plate").keys()

    plate_grade = Job().steel_grades("Plate").keys()[0]   

    # end script defaults

    ######################################################################################################################

    # Function definitions

    ###########################################################################

    def apply_stud(mem, pt11, pt12, _stud_diam, _head_thk, _head_diam, _stud_color, rot_args):

        # shear stud begin

        m1 = ShrStud()

        m1.member = mem

        m1.pt1 = pt11

        m1.pt2 = pt12

        m1.stud_dia = _stud_diam

        m1.head_thick = _head_thk

        m1.head_dia = _head_diam

        m1.length = m1.pt1.dist(m1.pt2)

        m1.mtrl_type = "Shear stud"

        m1.mtrl_usage = "Embed_Plate_Stud"

        m1.finish = _stud_color

        m1.ref_pt_offset = (0.000000, 0.000000, 0.000000)

        m1.add()

        m1.rotate(m1.member, rot_args)

        # shear stud end

 

    # function to return default number of stud columns, stud rows, embed plate length,

    # embed plate depth, embed plate thickness, user_piece_mark

    def embed_plate_dims(mem):

        if mem.nom_depth <= 11.9:

            return (2, 2, 10.0, 12.0, 0.75, "EM_W12") # W4, W6, W8, W10

        elif mem.nom_depth <= 13.9:

            return (2, 2, 10.0, 12.0, 0.75, "EM_W12") # W12

        elif mem.nom_depth <= 15.9:

            return (2, 3, 10.0, 18.0, 0.75, "EM_W16") # W14

        elif mem.nom_depth <= 17.9:

            return (2, 3, 10.0, 18.0, 0.75, "EM_W16") # W16

        elif mem.nom_depth <= 20.9:

            return (2, 4, 10.0, 24.0, 0.75, "EM_W18") # W18

        elif mem.nom_depth <= 23.9:

            return (2, 5, 10.0, 30.0, 0.75, "EM_W24") # W21

        elif mem.nom_depth <= 26.9:

            return (2, 5, 10.0, 30.0, 0.75, "EM_W24") # W24

        elif mem.nom_depth <= 29.9:

            return (2, 6, 10.0, 36.0, 0.75, "EM_W30") # W27

        elif mem.nom_depth <= 32.9:

            return (2, 6, 10.0, 36.0, 0.75, "EM_W30") # W30

        elif mem.nom_depth <= 35.9:

            return (2, 7, 10.0, 42.0, 0.75, "EM_W36") # W33

        else:

            return (2, 7, 10.0, 42.0, 0.75, "EM_W36") # any beam W36 or deeper

 

    # define function to add the miscellaneous member, rectangular plate

    def add_misc_rect_plate(pnt1, pnt2, mk, pd, pt, rot, grade, seq):

        # member begin

        memadd5 = Member('Misc Rectangular Plate')

        memadd5.left.location = pnt1

        memadd5.right.location = pnt2

        memadd5.piecemark = mk

        memadd5.grade = grade

        memadd5.origin = "FS"

        memadd5.top_oper_left = "None"

        memadd5.top_oper_right = "None"

        memadd5.bottom_oper_left = "None"

        memadd5.bottom_oper_right = "None"

        memadd5.width = pd

        memadd5.thick = pt

        memadd5.work_pt_dist = memadd5.left.location.dist(memadd5.right.location)

        memadd5.setback_left = 0

        memadd5.setback_right = 0

        memadd5.length = memadd5.work_pt_dist - memadd5.setback_left - memadd5.setback_right

        memadd5.mtrl_type = "Plate"

        memadd5.mtrl_usage = "Embed_Plate"

        memadd5.finish = "Galvanized"

        memadd5.ref_pt_offset = (0, 0, 0)

        memadd5.description = "Embedded Plate"

        # memadd5.sequence = str(seq)

        memadd5.add()

        memadd5.rotate(rot)

        # member end

        return memadd5

 

    # function to add holes to the embedded plate

    def pl_holes (mem, ref_pt, edge_dist, pattern_orientation, hz):

        # hole group add begin

        hole26 = Hole()

        hole26.mtrl = [mem, ]

        hole26.pt1 = ref_pt

        hole26.hole_type = "Standard Round"

        hole26.face = "NS Face"

        hole26.valid_cnc = "Yes"

        hole26.x_ref_offset = edge_dist

        hole26.y_ref_offset = edge_dist

        hole26.x_spa = 3.0

        hole26.y_spa = 3.0

        hole26.group_rot = 0.0

        hole26.locate = pattern_orientation

        hole26.columns = 1

        hole26.rows = 1

        hole26.bolt_type = "Auto"

        hole26.bolt_dia = hz - 0.0625

        hole26.hole_dia = hz

        hole26.show_window = "No"

        hole26.create()

        # hole group add end

        return hole26

    # end function definitions

    ###########################################################################

    ## Import default values if enabled

    if enable_default_import_export == "Enable":

        dd0 = import_data(os.path.join(default_file_path, def_file))

        if dd0:

            for key, value in dd0.items():

                exec "%s = %s" % (key, repr(value)) in None

           

    #################################################################

    ## Main program loop

    while True:

        misc_list = mem_select("Select BEAM member or ENTER to exit", ['Beam',], ["W flange", "Tube", "Channel", "S Shape", "All"])

        if misc_list is None:

            break

        mem1 = misc_list[0]

               

        head_thk, head_diam, burn_off = stud_dim(dim(stud_diam)) # determine stud dimensions based upon stud diameter

 

        no_cols, no_rows, plate_length, plate_depth, plate_thick, user_piece_mark = embed_plate_dims(misc_list[0])

       

        try:

            plate_seq = int(plate_seq)

        except:

            pass

        ## DIALOG BOX 1 #################################

        dlg1 = Dialog( "Create an embedded plate member" )

        dlg1.menu("print_doc", ("Yes", "No"), "No", "Print parametric script documentation only")

       

        dlg1.tabset_begin()

        dlg1.tab("Embed general information")

        dlg1.group_title("Embedded plate location and plan rotation")

        dlg1.menu("which_end", ("Left End", "Right End"), which_end, "Place embed at which end of beam member                        ")

        dlg1.line("Embed rotation of 0 degrees - Member line left to right - Studs toward bottom of screen")

        dlg1.line("Embed rotation of 180 degrees - Member line left to right - Studs toward top of screen")

        dlg1.entry("embed_plan_rotation", embed_plan_rotation, "Embed plan rotation")

        dlg1.entry("embed_vertical_offset", dim_print(embed_vertical_offset), "Distance from top of embed to top of beam")

        dlg1.group_title_end

       

        dlg1.group_title("Embedded plate piece mark and material grade")

        dlg1.menu("embed_mark_system_user", ("User", "System"), embed_mark_system_user, "User or System Piece Mark")

        dlg1.entry("user_piece_mark", user_piece_mark, "User Piece Mark")

        dlg1.menu("plate_grade", Job().steel_grades("Plate").keys(), plate_grade, "Plate Material Grade")

        dlg1.entry("plate_seq", plate_seq, "Embed Member Sequence")

        dlg1.group_title_end

       

        dlg1.group_title("Embedded plate dimensions")

        dlg1.entry("plate_length", dim_print(plate_length), "Plate plan length")

        dlg1.entry("plate_depth", dim_print(plate_depth), "Plate vertical depth")

        dlg1.entry("plate_thick", dim_print(plate_thick), "Plate thickness")

        dlg1.group_title_end

       

        dlg1.tab("Stud Information")

        dlg1.group_title("Stud attributes")

        dlg1.label(dim_print(head_diam) + " diam. x " + dim_print(head_thk), "Stud head dimensions for default stud diameter: ")

        dlg1.label(dim_print(burn_off), "Burn off for default diameter: ")

        dlg1.menu("stud_diam", stud_diaList, stud_diam, "Stud diameter")

        dlg1.entry("stud_length", dim_print(stud_length), "Stud length")

        dlg1.menu("stud_color", finishList, stud_color, "Finish of stud material")

        dlg1.group_title_end

       

        dlg1.group_title("Stud Pattern")

        dlg1.entry("no_cols", int(no_cols), "Number of stud columns")

        dlg1.entry("no_rows", int(no_rows), "Number of stud rows")

        dlg1.entry("x_spa", dim_print(x_spa), "Horizontal stud spacing")

        dlg1.entry("z_spa", dim_print(z_spa), "Vertical stud spacing")

        dlg1.entry("x_off", dim_print(x_off), "Horizontal pattern offset")

        dlg1.entry("z_off", dim_print(z_off), "Vertical pattern offset (+ = UP)")

        dlg1.group_title_end

       

        dlg1.tab("Nailer Holes")

        dlg1.menu("add_nailer_holes", (0, 2, 4), int(add_nailer_holes), "Number of nailer holes          ")

        dlg1.entry("nailer_hole_size", dim_print(nailer_hole_size), "Nailer hole size")

        dlg1.entry("nailer_edge_dist", dim_print(nailer_edge_dist), "Nailer hole edge distance")

       

        dlg1.group_title("Image of embed plate with 180 degree plan rotation")

        dlg1.image(image_name4)

        dlg1.group_title_end

       

        dlg1.tab("Graphic Images")

        dlg1.column_group_begin()

        dlg1.column(5)

        dlg1.image(image_name1)

        dlg1.column(5)

        dlg1.image(image_name2)

        dlg1.column_group_end()

        dlg1.tabset_end()

       

        try:

            dd1 = dlg1.done()

        except ResponseNotOK:

            break

 

        # Update the local namespace

        for key, value in dd1.items():

            exec "%s = %s" % (key, repr(value)) in None   

        ###################################################

        ## END DIALOG BOX 1 ------------------------------#

        ###################################################

        if print_doc == "Yes":

            print __doc__

            break

       

        # Export defaults to disk if enabled

        if enable_default_import_export == "Enable":

            export_data(os.path.join(default_file_path, def_file), dd1)

        #############################################################

           

        # Adjust plan rotation angle

        while embed_plan_rotation < -180.0:

            embed_plan_rotation = embed_plan_rotation + 360.0

        while embed_plan_rotation > 180.0:

            embed_plan_rotation = embed_plan_rotation - 360.0

           

        # Set material rotations

        if embed_plan_rotation <= 90.0 and embed_plan_rotation > -90.0:

            # studs below member line

            rot_mat = (0.0, 0.0, -90.0)

            plate_rot = 0.0

        else:

            # studs above member line

            rot_mat = (0.0, 0.0, 90.0 )

            plate_rot = 180.0

       

        # Set stud dimensions

        head_thk, head_diam, burn_off = stud_dim(dim(stud_diam))

        ###########################################################################################

        for mi in range(len(misc_list)):

            if embed_mark_system_user == "System":

                _mark_ = ""

            else:

                _mark_ = user_piece_mark

            if which_end == "Left End":

                ptWP1 = polar_pt_plan(misc_list[mi].left_location, -plate_length/2, embed_plan_rotation)

                ptWP2 = polar_pt_plan(misc_list[mi].left_location, plate_length/2, embed_plan_rotation)

            if which_end == "Right End":

                ptWP1 = polar_pt_plan(misc_list[mi].right_location, -plate_length/2, embed_plan_rotation)

                ptWP2 = polar_pt_plan(misc_list[mi].right_location, plate_length/2, embed_plan_rotation)

            ptWP1 = Point (ptWP1.x, ptWP1.y, ptWP1.z + embed_vertical_offset)

            ptWP2 = Point (ptWP2.x, ptWP2.y, ptWP2.z + embed_vertical_offset)

 

            # Add member

            mem_added = add_misc_rect_plate(ptWP1, ptWP2, _mark_, plate_depth, plate_thick, \

                                            (90.0, 0.0, plate_rot), plate_grade, plate_seq)

            # Add nailer holes

            if add_nailer_holes == 2 or add_nailer_holes == 4:

                ptWP3 = ptWP1 + mem_added.main_mtrl().translate (0.0, -plate_depth, 0.0)

                ptWP4 = ptWP2 + mem_added.main_mtrl().translate (0.0, -plate_depth, 0.0)

                pl_holes (mem_added, ptWP1, nailer_edge_dist, "Below Right", nailer_hole_size)

                pl_holes (mem_added, ptWP4, nailer_edge_dist, "Above Left", nailer_hole_size)

            if add_nailer_holes == 4:

                pl_holes (mem_added, ptWP3, nailer_edge_dist, "Above Right", nailer_hole_size)

                pl_holes (mem_added, ptWP2, nailer_edge_dist, "Below Left", nailer_hole_size)

            # Add studs

            first_dist_horiz = ((plate_length - x_spa * (no_cols - 1)) / 2) + x_off

            first_dist_vert = ((plate_depth - z_spa * (no_rows - 1)) / 2) - z_off

            point1 = mem_added.left_location + \

                     mem_added.main_mtrl().translate (first_dist_horiz, -first_dist_vert, plate_thick)

            x_dist = 0.0

            for i in range(no_cols):

                z_dist = 0.0

                x_dist = i*x_spa

                for j in range(no_rows):

                    z_dist = j*z_spa

                    ptWP = point1 + mem_added.main_mtrl().translate (x_dist, -z_dist, 0.0)

                    apply_stud(mem_added, ptWP, Point(ptWP.x, ptWP.y - stud_length, ptWP.z), \

                               dim(stud_diam), head_thk, head_diam, stud_color, rot_mat)

 

## End run_script()

if __name__ == '__main__':

    try:

        run_script()

    finally:

        del run_script