##  Col_BntPLConn.py Version 1.00

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

##  All rights reserved.

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

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

"""

Add a one-sided bent plate to a WF or Tube column as a connection for a selection set of skewed WF beams -

The bent plate is welded to the column, and the beam field bolts to the bent plate.

The bent plate orientation can be conventional, hooked, wrapped, or hooked and wrapped.

The hooked bent plate orientation is not applicable to tube columns. The bent plate will be attached

to the flange of a wide flange column. The bent plate can be attached to the short side (flange), the

long side (web), or both sides (for a knife connection) of a tube column.

The the work point of the beam should coincide with the column CL. The script will work if the WP

location offsets, but the user will have to manually move the bent plate into the proper location.

 

The calculates and sets the proper beam minus dimension.

 

The script adds a hole pattern to the beam web and matches for bolting.   

 

This script can be executed in plan, elevation, or isometric, and was tested in SDS/2 7.111.

This script was originally developed in SDS/2 versions 6.244, 6.314, and 7.002. This script

does not work in SDS/2 versions earlier than 7.111.

 

This script can be executed in plan, elevation, or isometric.

 

Version History:

    1.00 (11/16/07) - Update code and rewrite for latest version of SDS/2 (7.111)

 

NOTE:

The beam end distance from the bolt column is hard coded 2*bolt_diameter.                          

 

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

#### NOTE: This version is not compatible with SDS/2 7.0 ####

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

 

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

For comments, suggestions or questions call BV at the number above, email bvdet@comcast.net,

or post to SDS/2 forum.

 

Go to defaults section to set script defaults.

"""

# startup code begin

import os

import sys

 

from macrolib.FileDefaults import import_data, export_data

from macrolib.L3D import LineLineIntersect3D, ret_WP

from macrolib.angle import rtod, dtor, angle_between_members

from macrolib.ExceptWarn import formatExceptionInfo

from macrolib.bp_data import BPdata

from macrolib.MemSelection import mem_select, memAreaSelect

from macrolib.Weld import mtrl_weld

from macrolib.bolt_match import bolt_match, hole_bolt_match

from macrolib.round_length import round_length_near

 

from param import *

from math import *

Units("feet")

from shape import Shape

from point import Point, PointLocate

from member import Member, MemberLocate

from mtrl_list import MtrlLocate, HoleLocate, MtrlByGuid

from rect_plate import RectPlate

from bnt_plate import BntPlate

from rolled_section import RolledSection

from hole_add import Hole

from bolt_add import Bolt

from job import Job, ProcessJob, ProcessOneMem

from fab import Fabricator

 

epsilon = 0.000001

 

# startup code end

 

def run_script():

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

    ## Variables section

    # system path for defaults file

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

 

    # defaults file name

    def_file = "Col_BntPLConn.txt"

 

    # Path to image files and file names

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

    image_name = os.path.join(image_path, "Col_BntPLConn.gif")

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

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

    image_name3 = os.path.join(image_path, "Col_BntPLConn3.gif")

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

    # enable or disable the importing and exporting of dialog dictionary

    # variables "Enable" "Disable"

    enable_default_import_export = "Enable"

 

    holetypeList = ["Standard Round", "Short Slot", "Oversized Round", "Long Slot"]

    finishList = ["None", "Red Oxide", "Yellow Zinc", "Gray Oxide", "Sandblasted", "Blued Steel", "Galvanized"]

    conntypeList = ["Conventional", "Hooked", "Wrapped", "HookWrap"]

    bolttypeList = Job().bolt_sched()

    weldtypeList = ["Fillet", ]

    weldsizeList = ['3/16', '1/4', '5/16', '3/8', '7/16', '1/2']

    sideList = ["Short Side", "Long Side", "Both Sides"]

    boltOptionsList = ["Match Holes", "Match Holes/Bolts", "Process", "Do Nothing"]

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

    ## Defaults section

    # cut a section at the bent plate "Yes", "No"

    cut_sect = "Yes"

    # option for matching holes and adding bolts to beam material

    boltOptions = "Process"

    # bent plate orientation - conntypeList

    conn_type = "Conventional"

    # distance to first hole from T/S

    dist_1st = 3.0

    # number of bolt columns (2 columns = double gage)

    no_cols = 1

    # spacing of bolt rows

    row_spa = 3.0

    # spacing of bolt columns

    col_spa = 3.0

    # gage on bent plate material from outside bend corner

    bp_ga = 2.5

    # thickness of bent plate material

    bp_thk = 0.375

    # edge distance at end of bp material

    end_ed = 1.5

    # horizontal edge distance

    hor_ed = 1.5

    # width of bent plate leg attached to column

    osl_width = 4.0

    # bent plate material finish

    mtrl_finish = "Gray Oxide"

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

    mtrl_grade = "A36"

    # bolt diameter

    bolt_size = 0.75

    # hole type in web leg - holetypeList

    hole_type_web = "Short Slot"

    # bolt type in web leg - bolttypeList

    bolt_type_web = "A325N"

    # Welding

    add_weld = "Yes"

    # weld type

    weld_type = "Fillet"

    # weld size - weldsizeList

    weld_size = 0.25

    # weld all around "No" "Yes"

    weld_around = "No"

    # if column is HSS, add bent plate to flange or web

    # "Short Side", "Long Side", "Both Sides"

    bp_location = "Short Side"

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

    ## Function definition section ######

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

    # function to add bent plate material

    def add_bent_pl (mem, p1, mtrl_length, grade, thk, bend, bolt_leg, col_leg, finish, rot):

        # bent plate begin

        bp1 = BntPlate()

        bp1.member = mem

        bp1.pt1 = p1

        bp1.pt2 = p1 + mem.translate(mtrl_length, 0.0, 0.0)

        bp1.grade = grade

        bp1.centered = "No"

        bp1.thick = thk

        bp1.bend_angle = bend

        bp1.bend_radius = thk

        bp1.leg = bolt_leg

        bp1.osl = col_leg

        bp1.work_pt_dist = bp1.pt1.dist(bp1.pt2)

        bp1.setback_left = 0

        bp1.setback_right = 0

        bp1.length = bp1.work_pt_dist - bp1.setback_left - bp1.setback_right

        bp1.mtrl_type = "Bent plate"

        bp1.mtrl_usage = "one-sided BPL"

        bp1.finish = finish

        bp1.ref_pt_offset = (0.000000, 0.000000, 0.000000)

        bp1.add()

        bp1.rotate(bp1.member, rot)

        # bent plate end

        return bp1

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

    # function to add a hole pattern to the bent plate material

    def add_bp_holes (m, patt_WP, ht, xs, ys, cols, rows, bt, bd):

        # hole group add begin

        hole4 = Hole()

        hole4.mtrl = [m, ]

        hole4.pt1 = hole4.mtrl.location + hole4.mtrl.translate(patt_WP[0], -patt_WP[1], 0.000000)

        hole4.hole_type = ht

        hole4.face = "Web FS"

        hole4.valid_cnc = "Yes"

        hole4.x_ref_offset = 0

        hole4.y_ref_offset = 0

        hole4.x_spa = xs

        hole4.y_spa = -ys

        hole4.group_rot = 0

        hole4.locate = "Below Right"

        hole4.columns = cols

        hole4.rows = rows

        hole4.bolt_type = bt

        hole4.bolt_dia = bd

        hole4.slot_rot = 90.0

        hole4.length = hole4.calc_slot_length()

        hole4.hole_dia = hole4.calc_hole_size()

        hole4.show_window = "Yes"

        hole4.create()

        # hole group add end

        return hole4

 

    # function to add a hole pattern to the beam material

    def add_bm_holes (bm, pt, ht, ys, xs, rows, cols, bt, bd, we):

        if we == "left end":

            loc = "Below Right"

        else:

            loc = "Below Left"

        # hole group add begin

        hole4 = Hole()

        hole4.mtrl = [bm, ]

        hole4.pt1 = bm.left.location

        hole4.hole_type = ht

        hole4.face = "Web NS"

        hole4.valid_cnc = "Yes"

        hole4.x_ref_offset = pt.x

        hole4.y_ref_offset = pt.y

        hole4.x_spa = xs

        hole4.y_spa = ys

        hole4.group_rot = 0

        hole4.locate =loc

        hole4.columns = cols

        hole4.rows = rows

        hole4.bolt_type = bt

        hole4.bolt_dia = bd

        hole4.slot_rot = 0.0

        hole4.length = hole4.calc_slot_length()

        hole4.hole_dia = hole4.calc_hole_size()

        hole4.show_window = "Yes"

        hole4.create()

        # hole group add end

        return hole4

 

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

    # define function to return default number of bolt rows

    # (bolt columns with respect to bent plate material)

    def row_list(mem):

        try:

            return Job().min_shear(mem.nom_depth).num_rows

        except:

            return 3

 

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

    ####### End function definitions section ##################

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

    # if enabled, import defaults used previously from disk file

    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:

        try:

            ClearSelection()

            # Section for member selection

            colList = mem_select("Select a WF or TUBE COLUMN member", ['Column', ], \

                                 ['W flange', 'Tube'], single=True, all_mks=False)

            if not colList:

                break

            mem1 = colList[0]

           

            bmList = memAreaSelect("Select WF BEAM members by area for connection", \

                                   ["Beam"], ['W flange',])

            if not bmList:

                Warning("You did not pick any beams of the right material type. Exiting script.")

                break

            ## Begin beam loop ####################################

            for bi, bm in enumerate(bmList):

                no_rows = row_list(bm)

                if isinstance(weld_size, str):

                    weld_size = dim(weld_size)

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

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

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

                dlg1 = Dialog( "Beam to column one-sided bent plate connection" )

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

                dlg1.line("Column (%s, %s) Plan rotation: %0.4f" % (mem1.piecemark, mem1.section_size, mem1.rotation))

                dlg1.line("Beam (%s, %s) Plan rotation: %0.4f" % (bm.piecemark, bm.section_size, bm.plan_rotation))

                dlg1.tabset_begin()

                dlg1.tab("General")

                dlg1.group_title("General options (**not available in this version of SDS/2")

                dlg1.menu("conn_type", conntypeList, conn_type, "Connection orientation                     ")

                dlg1.menu("boltOptions", boltOptionsList, boltOptions, "Hole match options")

                dlg1.menu("cut_sect", ['Yes', 'No'], cut_sect, "Cut a column section**")

                dlg1.menu("mtrl_grade", Job().steel_grades("Plate").keys(), mtrl_grade, "Material grade")

                dlg1.menu("mtrl_finish", finishList, mtrl_finish, "Material finish")

                if mem1.mtrl_type == "Tube":

                    dlg1.menu("bp_location", sideList, bp_location, "Apply bent plate to which side?")

 

                dlg1.group_title("Connection options")

                dlg1.entry("dist_1st", dim_print(dist_1st), "Distance to first bolt row")

                dlg1.entry("no_rows", no_rows, "Number of bolt rows")

                dlg1.entry("no_cols", no_cols, "Number of bolt cols")

                dlg1.entry("row_spa", dim_print(row_spa), "Bolt row spacing")

                dlg1.entry("col_spa", dim_print(col_spa), "Bolt column spacing")

                dlg1.entry("bp_ga", dim_print(bp_ga), "Gage to 1st bolt column")

                         

                dlg1.group_title("Bent plate dimensions" )

                dlg1.entry("osl_width", dim_print(osl_width), "Leg width against column")

                dlg1.entry("bp_thk", dim_print(bp_thk), "Thickness of bent plate")

                dlg1.entry("end_ed", dim_print(end_ed), "BPL end edge distance")

                dlg1.entry("hor_ed", dim_print(hor_ed), "BPL horiz edge distance")

 

                dlg1.tab("Bolts/Holes")

                dlg1.group_title("Bolt options")

                dlg1.entry("bolt_size", dim_print(bolt_size), "Enter bolt diameter")

                dlg1.menu("bolt_type_web", bolttypeList, bolt_type_web, "Bolt type in bent plate")

                dlg1.menu("hole_type_web", holetypeList, hole_type_web, "Hole type in bent plate")

                dlg1.group_title("Wrapped bent plate connection")

                dlg1.image(image_name3)

           

                dlg1.tab("Weld" )

                dlg1.group_title("General Information")

                dlg1.menu("add_weld", ("Yes", "No"), add_weld, "Add bent plate to column weld" )

                dlg1.menu("weld_type", weldtypeList, weld_type, "Weld type")

                dlg1.menu("weld_size", weldsizeList, dim_print(weld_size), "Weld size")

                dlg1.menu("weld_around", ("Yes", "No"), weld_around, "Weld all around")

                dlg1.group_title("Knifed bent plate connection")

                dlg1.image(image_name4)

               

                dlg1.tab("Graphic")

                dlg1.image(image_name)

                dlg1.tab("Image")

                dlg1.line("Hooked bent plate connection")

                dlg1.image(image_name1)

                dlg1.line("Conventional bent plate connection")

                dlg1.image(image_name2)

                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 enable_default_import_export == "Enable":

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

                   

                if print_doc == "Yes":

                    print __doc__

                    break       

                   

                # sets option to flange if column is not a tube

                if mem1.mtrl_type == "W flange":

                    bp_location = "Short Side"

 

 

                # Check for invalid orientation

                if mem1.mtrl_type == "Tube":

                    if bp_location == "Both Sides" and conn_type != "Conventional":

                        conn_type = "Conventional"

                        Warning("Column has tube material - a conventionally oriented bent plate will be substituted for the specified orientation.")

                    elif conn_type == "Hooked":

                        conn_type = "Conventional"

                        Warning("Column has tube material - a conventionally oriented bent plate will be substituted for a hooked one.")

                    elif conn_type == "HookWrap":

                        conn_type = "Wrapped"

                        Warning("Column has tube material - a wrapped oriented bent plate will be substituted for a hooked/wrapped one.")

               

                # determine connection WP and which end of member

                ref_pt, which_end = ret_WP(mem1, bm)

               

                if bp_location == "Both Sides":

                    loc_list = ["Short Side", "Long Side"]

                    e_clr = 0.125

                else:

                    loc_list = [bp_location, ]

                    e_clr = 0.0

 

                beam_updated = False

                bpList = []

                for si in loc_list:

                    # determine angular relationship and case number

                    hss_flg_web = si

                    a = BPdata(mem1, bm, hss_flg_web, which_end, conn_type, bp_ga, bp_thk, e_clr)

                    rel_rotation = a.relRot

                    rotList = a.rot

                    case_no = a.caseno

                    bend_angle = a.bendAng

                    x_off, y_off, z_dist = a.xyz_offsets()

 

                    # determine bent plate gage to use if knife connection         

                    if bp_location == "Both Sides":

                        zoffSS = BPdata(mem1, bm, "Short Side", which_end, conn_type, bp_ga, bp_thk, e_clr).xyz_offsets()[2]

                        zoffLS = BPdata(mem1, bm, "Long Side", which_end, conn_type, bp_ga, bp_thk, e_clr).xyz_offsets()[2]

                       

                        if zoffSS < zoffLS and hss_flg_web == "Short Side":

                            bp_ga1 = bp_ga + zoffLS - zoffSS

                            z_dist = z_dist + zoffLS - zoffSS

                        elif zoffLS < zoffSS and hss_flg_web == "Long Side":

                            bp_ga1 = bp_ga + zoffSS - zoffLS

                            z_dist = z_dist + zoffSS - zoffLS

                        else:

                            bp_ga1 = bp_ga

                    else:

                        bp_ga1 = bp_ga

                        

                    # Calculate dimensions and work points

                    matl_length = (end_ed * 2.0) + ((no_rows - 1) * row_spa)

                    webleg_width = round_length_near(bp_ga1 + (no_cols - 1) * col_spa + hor_ed, '1/16')

                   

                    bp_WP = ref_pt + mem1.translate(0.0, -x_off, -y_off)

                    ptWP1 = bp_WP - mem1.translate(dist_1st - end_ed, 0.0, 0.0)

                    ptWP2 = ptWP1 - mem1.translate(matl_length, 0.0, 0.0)

 

                    if not beam_updated:

                        # set the beam end to plain end, change setback, process

                        if which_end == 'left end':

                            bm.left.auto_minus_dim = "No"

                            bm.left.minus_dim = round_length_near(z_dist-(bolt_size*2), '1/16')

                            bm.left.auto_setback = "No"

                            bm.left.setback = bm.left.minus_dim

                            bm.left.input_conn_type = 'Plain end'

                        else:

                            bm.right.auto_minus_dim = "No"

                            bm.right.minus_dim = round_length_near(z_dist-(bolt_size*2), '1/16')

                            bm.right.auto_setback = "No"

                            bm.right.setback = bm.right.minus_dim

                            bm.right.input_conn_type = 'Plain end'

                        bm.update()

                        try:

                            ProcessOneMem(bm.number)

                        except:

                            Warning("Member process failed")

                        beam_updated = True

                        bm = Member(bm.number)

                   

                    # add plate material, holes, and weld

                    if case_no == "Case 2" or case_no == "Case 4":

                        if hss_flg_web == "Short Side":

                            bp11 = add_bent_pl (mem1, ptWP1, matl_length, mtrl_grade, bp_thk, -bend_angle, \

                                                webleg_width, osl_width, mtrl_finish, rotList)

                        else:

                            bp11 = add_bent_pl (mem1, ptWP2, matl_length, mtrl_grade, bp_thk, -bend_angle, \

                                                webleg_width, osl_width, mtrl_finish, rotList)

                    else:

                        if hss_flg_web == "Short Side":

                            bp11 = add_bent_pl (mem1, ptWP2, matl_length, mtrl_grade, bp_thk, -bend_angle, \

                                                webleg_width, osl_width, mtrl_finish, rotList)

                        else:

                            bp11 = add_bent_pl (mem1, ptWP1, matl_length, mtrl_grade, bp_thk, -bend_angle, \

                                                webleg_width, osl_width, mtrl_finish, rotList)

                   

                    hlpatt = add_bp_holes(bp11, (end_ed, bp_ga1), hole_type_web, row_spa, col_spa, no_rows, \

                                          no_cols, bolt_type_web, bolt_size)           

                   

                    if add_weld == "Yes":

                        mtrl_weld([mem1, ], [bp11, ], weld_size, weld_type, around=weld_around)

                   

                    bpList.append(bp11)

                    

                # add hole pattern to the beam

                # "Match Holes", "Match Holes/Bolts", "Process", "Do Nothing"

                if boltOptions == "Match Holes":

                    hole_match(bm, hlpatt)

                elif boltOptions == "Match Holes/Bolts":

                    hole_bolt_match(bm, hlpatt, bpList)

                elif boltOptions == "Process":

                    try:

                        ProcessOneMem(bm.number)

                    except:

                        Warning("Process member failed")

                       

                '''

                ptLoc = bm.trans_to_local(hlpatt.pt1 - bm.left_location)

                add_bm_holes(bm, pt, "Standard Round", row_spa, col_spa, no_rows, no_cols, bolt_type_web, bolt_size, which_end)

                bolt_match(bp11, bm)

                '''

 

                if bi < len(bmList)-1:

                    if not yes_or_no("Dist from WP to first bolt column = %s (%0.4f)\rProceed?" % (dim_print(z_dist), z_dist)):

                        break

            # end beam loop

            if not yes_or_no("Dist from WP to first bolt column = %s (%0.4f)\nContinue?" % (dim_print(z_dist), z_dist)):

                break

        except:

            Warning(formatExceptionInfo())

            break

## END run_script() #######################################

if __name__ == '__main__':

    try:

        run_script()

    finally:

        ClearSelection()

        del run_script