##  Beam_Clips.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.

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

""" Beam_Clips

    Add clip Ls to the web at the end of a W flange, Channel, or Tube beam that frames into concrete or existing,

    or can add monorail clips to the beam web.

    Script reads member end material setback dimensions and sets the clips a selected distance from the end of material.

    This script will add continuous bar washers to cover long slots in the web leg if selected.

 

    If you select bolt type "Epoxy", "Hilti" or "Hilti_HAS" for the OSL, that type must exist in your job setup.

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

 

    Note:

        If user selects to add holes to member main material when prompted, the material will become graphical.

        A reprocess of the member will add the holes and bolts, and the material will remain system.

 

    Script History:

        R2 -    Fixed an error in clip_holes - hole spacing different than 3"

                Moved defaults before while 1: so last entries will be remembered

                Added Channel beams

        R3 -    Edited notes above - This script was tested in 6.233, which would double up on the bolts

                in the left end clips. The bolts are added properly in 6.232.

        R4 -    Omitted function beam_slope - use member attribute mem1.slope

        R5 -    Add function to set the default number of rows based upon the beam depth.

                Reorganize the input screen for clarity. Add dim_print variables.

        R6 -    Edit to work with SDS/2 version 6.310

                Hole group in bar washer modification:  "Below Right">>"Above Left", "FS Face">>"NS Face",

                0.0>>-90.0 group_rot, gage is positive instead of negative

                Update code and function row_list.

        R7 -    Adjust code so added material will project beyond end of beam material a fixed amount.

                Ignore beam minus dimension and use material setback as reference point (mem.left.setback or mem.right.setback)

                Create material list for matching holes and adding bolts (adding holes makes main material graphical).

        R8 -    Check for members with the same piecemark. Add option to apply to all like members. (10/26/03)

        R9 -    Add capability to Read/Write defaults from/to disk (dictionary dd1). This functionality requires that TextDB.py

                can be imported, therefore the file must be present along the SDS/2 path. In my case - C:\SDS2_6.3\lib\TextDB.py

                Go to line 69 to edit the default data paths and file names. A new dialog box was added for importing/exporting

                script defaults. Data file names are selected from a menu. User may want to enter the file names directly and will

                need to change dlg11.menu to dlg11.entry and remove the menu list. Default data is imported before primary dialog box

                (dd1) is displayed. Default data is exported after primary dialog box (dd1) is displayed.

        R10 -   Adjust hole pattern code in bar washer to work in SDS/2 6.323

        R11 -   Consolidate dim_print into dialog box

 

    V7R1 -  Test in SDS/2 7.002, update code

            Rework import/export defaults.

    Version 1.02 -  Rework import/export functions

    Version 1.03 -  Incorporate dd.file for selection of default file names

    Version 1.04 -  Add system path for defaults files

   

    Version 1.05 -  Remove support for SDS/2 Version 6.3xx

                    Rework dialog box

                    Add automatic import/export defaults to file feature

 

    Version 1.06 -  Modify member information in dialog box

    Version 1.07 (3/21/07) - Edit image and default paths

    Version 1.08 (9/23/07) - Add variable bolt_size_OSL

                             Add variables finishList and holetypeList

    Version 1.09 (9/30/07) - Pass calculation of ga_osl if end_or_mono == "End Clips"

 

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

    ****NOTE: This version is not compatible with SDS/2 6.3.****

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

           

    This source is provided "as is."  All warranties are disclaimed.

   

    Developed in SDS2 6.323 12/30/03 (R10) ***Will not work in prior versions***

    Tested in SDS2 6.323, Python 2.2.1 12/30/03 (R10)

    Tested in SDS/2 7.002, Python 2.2.1 8/18/04 V7R1

 

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

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

 

    NOT FOR SALE

 

    Go to defaults section to modify script defaults.

#

"""

# startup code begin

import os

import sys

import traceback

from param import *

from math import *

Units("feet")

saved_sds2_version = '7.023'

saved_python_version = (2, 3, 0, 'final', 0)

try:

    from shape import Shape

    from point import Point, PointLocate

    from member import Member, MemberLocate

    from mtrl_list import MtrlLocate, HoleLocate

    from cons_line import ConsLine

    from cons_circle import ConsCircle

    from rnd_plate import RndPlate

    from rect_plate import RectPlate

    from bnt_plate import BntPlate

    from rolled_section import RolledSection

    from weld_add import Weld

    from flat_bar import FlatBar

    from hole_add import Hole

    from bolt_add import Bolt

    from roll_plate import RollPl

    from sqr_bar import SqrBar

    from rnd_bar import RndBar

    from shr_stud import ShrStud

    from grate import Grate

    from grate_trd import GrateTrd

    from deck import Deck

    from mtrl_fit import MtrlFit

    from version import CurrentVersion, VersionCompare

    curr_version = CurrentVersion()

except ImportError:

    curr_version = 'None'

    def VersionCompare( v1, v2 ):

        return -1

if VersionCompare( curr_version, '6.311' ) >= 0:

    from job import Job

    from fab import Fabricator

if VersionCompare( curr_version, '6.312' ) >= 0:

    from plate_layout import PlateLayout

if VersionCompare( curr_version, '6.314' ) >= 0:

    from plate_layout import BntPlateLayout

if VersionCompare( curr_version, '6.4' ) >= 0:

    from mtrl_cut import MtrlCut

if VersionCompare( curr_version, '7.006' ) >= 0:

    from member import MemberAllocated

if VersionCompare( curr_version, '7.009' ) >= 0:

    from job import JobName

    from fab import FabricatorName

# startup code end

 

## Variables section ######################################

# system path for defaults file

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

 

# defaults file

def_file = "Beam_Clips.txt"

default_file_for_saving = "BmClips_XXX.txt"

 

# "Yes", "No"

default_save = "No"          

script_name = "Beam_Clips_v1.09.py"

 

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

enable_default_import_export = "Enable"

 

# Dialog box image path and file name

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

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

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

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

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

image_name5 = os.path.join(image_path, "Beam_Clips5.gif")

image_name6 = os.path.join(image_path, "Beam_Clips6.gif")

 

# Dialog box default Defaults file name and path

# default system path for defaults file

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

user_default_file_path = os.path.join(user_default_file_path_for_saving, "*txt")

 

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

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

 

## Defaults section #######################################

which_end = "Right"                      # default for which end to place clip Ls "Left" "Right" "Both"

which_side = "BS"                       # default side(s) for clips "BS" "NS" "FS"

clip_norm = "Vertical"                  # default if clips are normal to beam or vertical "Normal" "Vertical"

clip_size = "L5x3x3/8"                  # default for material size of clip angles

clip_color = "Gray Oxide"               # default clip angle color

steelgrade = "A36"                      # default steel grade for non-HSS material

dist_1st = "3"                          # default distance to first hole

hole_cc = "3"                           # default ctr to ctr hole spacing

edge_dist = "1 1/4"                     # default edge distance at clip ends (same for bar washer)

bar_wash = "Yes"                        # default whether bar washers are added over long slots in web leg-  bar washer will only be added over long slots

bw_width = "3"                          # default bar washer width

bw_thk = "5/16"                         # default bar washer thickness

bw_color = "Yellow Zinc"                # default bar washer color

 

bolt_size = "3/4"                       # default bolt diameter

bolt_size_OSL = "3/4"                   # default bolt diameter OSL

 

holes_in_web = "Yes"                    # default if holes are in web leg

hole_type_web = "Long Slot"             # default hole type in web leg

bolt_type_web = "A325N"                 # default bolt type in web leg - Job().bolt_sched()

ga_web_leg = "3"                        # default gage in web leg

holes_in_osl = "No"                     # default if holes are in OSL "Yes" "No"

hole_type_osl = "Standard Round"        # default hole type in OSL

bolt_type_osl = "A325N"                 # default bolt type in OSL - Job().bolt_sched()

ga_osl = "2"                            # default gage or hole centers in OSL

ga_or_ctr = "GA"                        # default of whether gage entered for ga_osl is the GOL or hole centers "GA" "CTR"

slot_length_web = "0"                   # default slot length - only applies to long slot - enter 0 to calculate slot length

conn_proj = "1"                         # Projection of end clips beyond end of material

monoclip_dist = "1-0"                   # Distance from end of material to face of monorail clips

hls_and_blts = "Add holes and bolts"    # "Do not add holes or bolts", "Add holes only", "Add holes and bolts"

end_or_mono = "End Clips"               # ("End Clips", "Monorail Clips")

## End defaults section

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

## Function definitions for saving default values to disk

## See Python file "Script_Defaults.py" for usage documentation

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

def import_data(file):

    try:

        ff = open(file)

    except:

        print "There was an error opening the default data file. Please check your directory path and that file exists."

        return 0

    else:

        dd = {}

        key_values_list = ff.readlines()[3:]

        ff.close()

        for ii in key_values_list:

            key_name, key_value = ii.split("=", 1)

            dd[key_name.strip()] = key_value.strip()

        return dd

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

def export_data(file_name, dd_list, script_name): # pass script name for default file

    try:

        f = open(file_name, "w")

        f.write("Defaults file for script " + script_name + "\nVariable Name = Value Name\n\n")

        for jj in dd_list:

            for key_name in jj.keys():

                key_value = jj[key_name]

                f.write("%s = %s\n" % (key_name, key_value))

        f.close()

    except:

        dd_list = 0

        print "There was an error exporting the default data to disk. Please check your directory path. "

    return dd_list

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

# convert radians to degrees

def rtod ( r ):

    return (r * 180.0 / pi)

# convert degrees to radians

def dtor ( d ):

    return (d * pi / 180.0)

# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# define function add a clip angle using global variables where possible

# returns a rolled shape object

def clip_angle(mem1, pnt1, pnt2, rot1):

    matl_type = Shape(clip_size).type()

    rot1 = (rot1[0], rot1[1], (rot1[2] - sl))

    # rolled section begin

    rl1 = RolledSection()

    rl1.member = mem1

    rl1.pt1 = pnt1

    rl1.pt2 = pnt2

    rl1.section_size = clip_size

    rl1.grade = steelgrade

    rl1.centered = "No"

    rl1.top_oper_left = "None"

    rl1.top_oper_right = "None"

    rl1.bottom_oper_left = "None"

    rl1.bottom_oper_right = "None"

    rl1.llv = "HZ."                     # Change to "VT." from "HZ." to work in 6.317

    rl1.toe_io = "In"

    rl1.rolling_op = "None"

    rl1.width = 0

    rl1.thick = 0

    rl1.field_weld_prep_left = "No"

    rl1.field_weld_prep_right = "No"

    rl1.cut_radius_left = 0

    rl1.cut_radius_right = 0

    rl1.web_setback_left = 0

    rl1.web_setback_right = 0

    rl1.angle_of_twist = 0

    rl1.mid_ordinate = 0

    rl1.bend_angle = 0

    rl1.bend_radius = 0

    rl1.rolled_offset = 0

    rl1.work_pt_dist = matl_length

    rl1.setback_left = 0

    rl1.setback_right = 0

    rl1.web_cut_angle_left = 0

    rl1.web_cut_angle_right = 0

    rl1.flange_cut_left = 0

    rl1.flange_cut_right = 0

    rl1.end_cut_left = "Standard Cut"

    rl1.end_cut_right = "Standard Cut"

    rl1.length = rl1.work_pt_dist - rl1.setback_left - rl1.setback_right

    rl1.mtrl_type = matl_type

    rl1.finish = clip_color

    rl1.ref_pt_offset = (0.000000, 0.000000, 0.000000)

    rl1.add()

    rl1.rotate(rl1.member, rot1)

    # rolled section end

    return rl1

# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# define function to add a bar washer using global variables where possible

# returns a rectangular plate object

def bw_add(mem1, pnt1, pnt2, rot1):

    rot1 = (rot1[0], rot1[1], (rot1[2] - sl))

    # rectangular plate begin

    rp1 = RectPlate()

    rp1.member = mem1

    rp1.pt1 = pnt1

    rp1.pt2 = pnt2

    rp1.grade = steelgrade

    rp1.origin = "FS"

    rp1.top_oper_left = "None"

    rp1.top_oper_right = "None"

    rp1.bottom_oper_left = "None"

    rp1.bottom_oper_right = "None"

    rp1.width = bw_width

    rp1.thick = bw_thk

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

    rp1.setback_left = 0

    rp1.setback_right = 0

    rp1.web_cut_angle_left = 0

    rp1.web_cut_angle_right = 0

    rp1.length = matl_length

    rp1.mtrl_type = "Plate"

    rp1.finish = bw_color

    rp1.ref_pt_offset = (0.000000, 0.000000, 0.000000)

    rp1.add()

    rp1.rotate(rp1.member, rot1)

    # rectangular plate end

    return rp1

# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# function to add holes to a bar washer using global variables where possible

def pl_holes (rl9):

    ga = bw_width / 2.0

    # hole group add begin

    hole26 = Hole()

    hole26.mtrl = [rl9, ]

    hole26.pt1 = hole26.mtrl.location

    hole26.hole_type = "Standard Round"

    hole26.face = "NS Face"

    hole26.valid_cnc = "Yes"

    hole26.x_ref_offset = edge_dist

    hole26.y_ref_offset = ga

    hole26.x_spa = hole_cc

    hole26.y_spa = hole_cc

    hole26.group_rot = 0.0

    hole26.locate = "Below Right"

    hole26.columns = no_rows

    hole26.rows = 1

    hole26.bolt_type = bolt_type_web

    hole26.bolt_dia = bolt_size

    hole26.slot_rot = 90.0

    hole26.length = hole26.calc_slot_length()

    hole26.hole_dia = hole26.calc_hole_size()

    hole26.show_window = "Yes"

    hole26.create()

    # hole group add end

    return hole26

# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# function to add holes to leg of clip L using global variables where possible

# slots are rotated perpendicular to length of material

def clip_holes (rl9, ga, bs, hltype, fa, bltype, slot_len):

    if slot_len:

        str = "slot_len"

    else:       

        str = "hole26.calc_slot_length()"

    # hole group add begin

    hole26 = Hole()

    hole26.mtrl = [rl9, ]

    hole26.pt1 = hole26.mtrl.location

    hole26.hole_type = hltype

    hole26.face = fa

    hole26.valid_cnc = "Yes"

    hole26.x_ref_offset = edge_dist

    hole26.y_ref_offset = ga

    hole26.x_spa = hole_cc

    hole26.y_spa = hole_cc

    hole26.group_rot = 0

    hole26.locate = "Below Right"

    hole26.columns = no_rows

    hole26.rows = 1

    hole26.bolt_type = bltype

    hole26.bolt_dia = bs

    hole26.slot_rot = 90.0

    hole26.length = eval(str)

    hole26.hole_dia = hole26.calc_hole_size()

    hole26.show_window = "Yes"

    hole26.create()

    # hole group add end

    return hole26

# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# function to match holes and add bolts xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# global variable accessed - hls_and_blts

def match_holes_bolts(mem_, hole_, matl_list):

    try:

        # hole group add begin

        hole9 = Hole()

        hole9.mtrl = [mem_,]

        hole9.holes = [hole_,]

        hole9.hole_type = "Standard Round"

        hole9.valid_cnc = "Yes"

        hole9.hole_dia = hole9.calc_hole_size()

        hole9.show_window = "No"

        hole9.create()

        # hole group add end

    except: pass

    if hls_and_blts == "Add holes and bolts":

        try:

            # bolt add begin

            bolt1 = Bolt()

            bolt1.mtrl = [mem_,]

            bolt1.match = matl_list

            bolt1.show_window = "No"

            bolt1.direction = "In"

            bolt1.add_match()

            # bolt add end

        except: pass

# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# define function to return list of members with the same piecemark

def member_count(mem):

    mem_index = 1

    no_mem = 0

    mem_list = []

    while no_mem < 100:   

        try:

            mem2 = Member(mem_index)

        except:

            mem_index = mem_index + 1

            no_mem = no_mem + 1

        else:

            if mem2.piecemark == mem.piecemark:

                mem_list.append(mem2)

            no_mem = 0

            mem_index = mem_index + 1

    return mem_list

# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# define function to return default number of rows based upon nominal material depth

def row_list(mem):

    return Job().min_struct(mem.nom_depth).num_rows # Look in clip angle table

    # return Job().min_shear(mem.nom_depth).num_rows  # Look in shear tab table

# define function to format global variables for this script

def form_script_variables():

    # All variables are defined as strings in defaults section. Defaults are saved to disk as dlg.done() defines them.

    # Default variables must be reformatted for imported data or for the second loop if not importing data.

    # Only floating point numbers need be reformatted. Integers should be formatted in the dialog box.

    global dist_1st

    global hole_cc

    global edge_dist

    global bw_width

    global bw_thk

    global bolt_size

    global ga_web_leg

    global ga_osl

    global slot_length_web

    global conn_proj

    global monoclip_dist

    dist_1st = dim_print(dim(dist_1st))

    hole_cc = dim_print(dim(hole_cc))

    edge_dist = dim_print(dim(edge_dist))

    bw_width = dim_print(dim(bw_width))

    bw_thk = dim_print(dim(bw_thk))

    bolt_size = dim_print(dim(bolt_size))

    ga_web_leg = dim_print(dim(ga_web_leg))

    ga_osl = dim_print(dim(ga_osl))

    slot_length_web = dim_print(dim(slot_length_web))

    conn_proj = dim_print(dim(conn_proj))

    monoclip_dist = dim_print(dim(monoclip_dist))

## End function definitions

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

# if enabled, import defaults used previously from disk file

if enable_default_import_export == "Enable":

    try:

        globals().update(import_data(os.path.join(user_default_file_path_for_saving, def_file)))

    except:

        Warning("There was a problem importing data - reverting to original defaults")

## Main program loop

while 1:

    ClearSelection()

    dd_list = []

    Add_clips = yes_or_no("Add clip Ls to the end of a beam?", "End Clips", "Monorail Clips", "Quit", "Import defaults from disk")

    if Add_clips == "Quit":

        break

    # Import defaults dialog box

    elif Add_clips == "Import defaults from disk":

        dlg11 = Dialog("Import script defaults from disk file")

        dlg11.file('import_file', user_default_file_path, "Enter file name or browse        ")

        dlg11.line("Choose end clip angles or monorail clip angles")

        dlg11.menu("end_or_mono", ("End Clips", "Monorail Clips"), end_or_mono, "End Clips or Monorail Clips?")

        try:

            dd11 = dlg11.done()

        except ResponseNotOK:

            break

        globals().update(dd11)

        dd_list = [dd11, ]

        try:

            globals().update(import_data(import_file))

        except:

            Warning("There was a problem importing data - reverting to original defaults")

    else:

        end_or_mono = Add_clips

    ## End Import/Export dialog box and import data ##################################################################################################

    # Select beam member

    bm_list = []

    z = 1

    while z:

        mem1 = MemberLocate("Select a BEAM member")

        if mem1 == None:

            break

        else:

            if mem1.type == "Beam":

                if mem1.mtrl_type in ["W flange", "Tube", "Channel", "W Tee", "S Shape"]:

                    # limit selection to one member

                    z = 0

                    bm_list.append(mem1)

                else:

                    Warning(mem1.mtrl_type + " beam material is not supported.")

            else:

                Warning("You picked a " + mem1.type + ". You must pick a Beam.")

    if len(bm_list) < 1:

        break

    chk_mem_list = member_count(bm_list[0])

    if len(chk_mem_list) > 1:

        if yes_or_no("Add clip Ls to all members with the same piecemark \r(" + str(len(chk_mem_list)) + " members with mark " + bm_list[0].piecemark + ")?") == 1:

            bm_list = chk_mem_list

    # Calculate default number of bolt rows and format defaults

    no_rows = row_list(bm_list[0])

    # If monorail clips are chosen, set clip orientation to 'normal', 'holes_in_osl' to 'No', bar_wash to 'No' and hole_type_web to 'Standard Round'

    if end_or_mono == "Monorail Clips":

        clip_norm = "Normal"

        holes_in_osl = "No"

        bar_wash = "No"

        hole_type_web = "Standard Round"

    # format default variables    

    form_script_variables()

    ## DIALOG BOX 1 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    dlg1 = Dialog("Add Clip Angles to Beam " + bm_list[0].piecemark)

    dlg1.tabset_begin()

    dlg1.tab("General Information")

    dlg1.column_group_begin()

    dlg1.column(0)

    dlg1.group_title("Clip Angle Location and Orientation")

    dlg1.menu("which_end", ("Left", "Right", "Both"), which_end, "Which end of beam                     ")

    dlg1.menu("which_side", ("BS", "NS", "FS"), which_side, "Which side(s) of beam web")

    if end_or_mono == "End Clips":

        dlg1.menu("clip_norm", ("Normal", "Vertical"), clip_norm, "Clip angle orientation")

    else:

        dlg1.line("Clip angle orientation is set to normal for monorail clips")

    dlg1.group_title_end

 

    dlg1.group_title(end_or_mono + " - Clip angle dimensions and bolt size.")

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

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

    dlg1.entry("hole_cc", hole_cc, "Center to center bolt rows")

    dlg1.entry("edge_dist", edge_dist, "End edge distance")

    dlg1.entry("bolt_size", bolt_size, "Bolt diameter web leg")

    dlg1.entry("bolt_size_OSL", bolt_size_OSL, "Bolt diameter OSL")

    dlg1.group_title_end

   

    if end_or_mono == "End Clips":

        dlg1.group_title("Clip angle projection along beam slope beyond end of material")

        dlg1.entry("conn_proj", conn_proj, "Amount of connection projection")

        dlg1.group_title_end

    else:

        dlg1.group_title("Distance from end of material to monorail clip angles")

        dlg1.entry("monoclip_dist", monoclip_dist, "Monorail clip distance")

        dlg1.group_title_end

   

    dlg1.group_title("Clip Angle Material Information")

    dlg1.entry("clip_size", clip_size, "Material size for clip Ls")

    dlg1.menu("steelgrade", Job().steel_grades("Angle").keys(), steelgrade, "Material grade")

    dlg1.menu("clip_color", finishList, clip_color, "Clip angle finish" )

    dlg1.group_title_end

   

    dlg1.column(0)

    dlg1.group_title("Member Information")

    dlg1.line("Member size: " + mem1.size + "        Piecemark: " + mem1.piecemark)

    dlg1.line("Left end location " + dim_print(mem1.left_location.x) + " , " +  dim_print(mem1.left_location.y) + " , " + dim_print(mem1.left_location.z))

    dlg1.line("Reaction Left end: " + " %0.1f"%bm_list[0].left.shear + " kips")

    dlg1.line("Reaction Right end: " + " %0.1f"%bm_list[0].right.shear + " kips")

    dlg1.group_title_end

    dlg1.group_title("Vertical and Normal Orientations")

    dlg1.column_group_begin()

    dlg1.column(0)

    dlg1.image(image_name5)

    dlg1.column(0)

    dlg1.image(image_name6)

    dlg1.column_group_end()

    dlg1.group_title_end

    dlg1.column_group_end()

   

    dlg1.tab("Bolts/Holes")

    dlg1.column_group_begin()

    dlg1.column(0)

    dlg1.group_title("Match holes/add bolts options" )

    dlg1.menu("hls_and_blts", ["Do not add holes or bolts", "Add holes only", "Add holes and bolts"], hls_and_blts, "Select option")

    dlg1.group_title_end

    dlg1.group_title("Bolt and hole type information web leg" )

    dlg1.menu("holes_in_web", ("Yes", "No"), holes_in_web, "Holes in web leg of clip")

    dlg1.entry("ga_web_leg", (ga_web_leg), "Gage in web leg")

    dlg1.menu("hole_type_web", holetypeList, hole_type_web, "Hole type in web leg of clip")

    dlg1.menu("bolt_type_web", Job().bolt_sched(), bolt_type_web, "Bolt type web leg of clip")

    if end_or_mono == "End Clips":

        dlg1.entry("slot_length_web", slot_length_web, "Long slot length in web leg")

    dlg1.group_title_end

   

   

    if end_or_mono == "End Clips":

        dlg1.group_title("Bolt and hole type information OSL")

        dlg1.menu("holes_in_osl", ("Yes", "No"), holes_in_osl, "Holes in outstanding leg of clip")

        dlg1.entry("ga_osl", ga_osl, "Gage or hole centers in OSL")

        dlg1.menu("ga_or_ctr", ("GA", "CTR"), ga_or_ctr, "OSL gage or C/C holes")

        dlg1.menu("hole_type_osl", holetypeList, hole_type_osl, "Hole type in OSL")

        dlg1.menu("bolt_type_osl", Job().bolt_sched(), bolt_type_osl, "Bolt type OSL")

        dlg1.group_title_end

    dlg1.column(0)

    dlg1.image(image_name1)

    dlg1.column_group_end()

 

    if end_or_mono == "End Clips":

        dlg1.tab("Bar Washer")

        dlg1.column_group_begin()

        dlg1.column(0)

        dlg1.group_title("Bar washer to cover long slots in web leg")

        dlg1.menu("bar_wash", ("Yes", "No"), bar_wash, "Add bar washers to web leg")

        dlg1.entry("bw_width", bw_width, "Bar washer width")

        dlg1.entry("bw_thk", bw_thk, "Bar washer thickness")

        dlg1.menu("bw_color", finishList, bw_color, "Bar washer color" )

        dlg1.group_title_end

        dlg1.group_title("Monorail and End Clips")

        dlg1.image(image_name4)

        dlg1.group_title_end

        dlg1.column(0)

        dlg1.image(image_name2)

 

    dlg1.tab("Default Save Options")

    dlg1.menu("default_save", ("Yes", "No"), default_save, "Save script defaults to a disk file?")

    dlg1.entry("user_default_file_path_for_saving", user_default_file_path_for_saving, "Enter path")

    dlg1.entry("default_file_for_saving", default_file_for_saving, "Enter file name")

   

    dlg1.tab("Graphic Image")

    dlg1.image(image_name)

 

    try:

        dd1 = dlg1.done()

    except ResponseNotOK:

        break

    globals().update(dd1)

    dd_list.append(dd1)

    ## End definition if dictionary dd1

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

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

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

    #------------------------------------------------------------|

    # If slot in web leg is not a long slot, set bar_wash to "NO"|

    #------------------------------------------------------------|

    if hole_type_web <> "Long Slot":

        bar_wash = "No"

        slot_length_web = 0.0

    #------------------------------------------------------------|

    # Export defaults to disk if enabled

    if enable_default_import_export == "Enable":

        export_data(os.path.join(user_default_file_path_for_saving, def_file), [dd1, ], script_name)

    # Export defaults to user defined file name

    if default_save == "Yes":

        export_data(os.path.join(user_default_file_path_for_saving, default_file_for_saving), dd_list, script_name)

    for bi in range(len(bm_list)):

        pt11 = bm_list[bi].left_location

        pt12 = bm_list[bi].right_location

        # find face of connection at top of steel

        if end_or_mono == "End Clips":

            end_dist = conn_proj

        else:

            end_dist = -monoclip_dist

        pt11 = pt11 + bm_list[bi].translate(bm_list[bi].left.setback - end_dist, 0.0, 0.0)

        pt12 = pt12 - bm_list[bi].translate(bm_list[bi].right.setback - end_dist, 0.0, 0.0)

        matl_length = (edge_dist * 2 + (no_rows - 1) * hole_cc)

        wp_to_corn = (dist_1st - edge_dist)

        web_gap = (ga_web_leg + (dim(bw_width) / 2))

        if bm_list[bi].mtrl_type == "W flange" or bm_list[bi].mtrl_type == "W Tee" or bm_list[bi].mtrl_type == "S Shape":

            web = bm_list[bi].tw

        elif bm_list[bi].mtrl_type == "Channel":

            web = bm_list[bi].tw

            if bm_list[bi].toeio == "In":

                pt11 = pt11 + bm_list[bi].translate(0.0, 0.0, bm_list[bi].tw / 2)

                pt12 = pt12 + bm_list[bi].translate(0.0, 0.0, bm_list[bi].tw / 2)

            else:

                pt11 = pt11 + bm_list[bi].translate(0.0, 0.0, -bm_list[bi].tw / 2)

                pt12 = pt12 + bm_list[bi].translate(0.0, 0.0, -bm_list[bi].tw / 2)

        else:

            web = bm_list[bi].short_depth

        if end_or_mono == "End Clips":

            # calculate angle gage if input is c/c holes, set ga_or_ctr to "GA"

            if ga_or_ctr == "CTR":

                ga_osl = ((ga_osl - web) / 2)

                ga_or_ctr = "GA"

        if clip_norm == "Normal":

            sl = 0.0

        else:

            sl = bm_list[bi].slope

        hole_match_matl_left = []

        hole_match_matl_right = []

        # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

        if end_or_mono == "End Clips":

            if which_end == "Left" or which_end == "Both":

                if which_side == "NS" or which_side == "BS":

                    pt21 = pt11 + bm_list[bi].translate( 0.0 - (sin(dtor(sl)) * wp_to_corn), -wp_to_corn * cos(dtor(sl)), web / 2)

                    pt22 = pt21 + bm_list[bi].translate( 0.0 - (sin(dtor(sl)) * matl_length), -matl_length * cos(dtor(sl)), 0.0)

                    rl22 = clip_angle(bm_list[bi], pt22, pt21, (0.0, 0.0, 90.0))

                    if holes_in_web == "Yes":

                        hole22 = clip_holes (rl22, ga_web_leg, bolt_size, hole_type_web, 2, bolt_type_web, slot_length_web)

                        hole_match_matl_left.append(rl22)

                        if bar_wash == "Yes":

                            pt61 = pt21 + bm_list[bi].translate( cos(dtor(sl)) * web_gap, -sin(dtor(sl)) * web_gap, Shape(clip_size).thick + bw_thk)

                            pt62 = pt61 + bm_list[bi].translate( -(sin(dtor(sl)) * matl_length), -matl_length * cos(dtor(sl)), 0.0)

                            rp62 = bw_add(bm_list[bi], pt62, pt61, (180.0, 0.0, 90.0))

                            pl_holes(rp62)

                            hole_match_matl_left.append(rp62)

                    if holes_in_osl == "Yes":

                        clip_holes (rl22, ga_osl, bolt_size_OSL, hole_type_osl, 1, bolt_type_osl, 0)

                if which_side == "FS" or which_side == "BS":

                    pt31 = pt11 + bm_list[bi].translate( -(sin(dtor(sl)) * wp_to_corn), -wp_to_corn * cos(dtor(sl)), -web / 2)

                    pt32 = pt31 + bm_list[bi].translate( -(sin(dtor(sl)) * matl_length), -matl_length * cos(dtor(sl)), 0.0)

                    rl33 = clip_angle(bm_list[bi], pt31, pt32, (180.0, 0.0, -90.0))

                    if holes_in_web == "Yes":

                        hole33 = clip_holes (rl33, ga_web_leg, bolt_size, hole_type_web, 2, bolt_type_web, slot_length_web)

                        hole_match_matl_left.append (rl33)

                        if bar_wash == "Yes":

                            pt71 = pt31 + bm_list[bi].translate( cos(dtor(sl)) * web_gap, -sin(dtor(sl)) * web_gap, -(Shape(clip_size).thick + bw_thk))

                            pt72 = pt71 + bm_list[bi].translate( -(sin(dtor(sl)) * matl_length), -matl_length * cos(dtor(sl)), 0.0)

                            rp72 = bw_add(bm_list[bi], pt71, pt72, (0.0, 0.0, -90.0))

                            pl_holes(rp72)

                            hole_match_matl_left.append(rp72)

                    if holes_in_osl == "Yes":

                        clip_holes (rl33, ga_osl, bolt_size_OSL, hole_type_osl, 1, bolt_type_osl, 0)

            if which_end == "Right" or which_end == "Both":

                if which_side == "NS" or which_side == "BS":

                    pt41 = pt12 + bm_list[bi].translate( -(sin(dtor(sl)) * wp_to_corn), -wp_to_corn * cos(dtor(sl)), web / 2)

                    pt42 = pt41 + bm_list[bi].translate( -(sin(dtor(sl)) * matl_length), -matl_length * cos(dtor(sl)), 0.0)

                    rl44 = clip_angle(bm_list[bi], pt41, pt42, (0.0, 0.0, -90.0))

                    if holes_in_web == "Yes":

                        hole44 = clip_holes (rl44, ga_web_leg, bolt_size, hole_type_web, 2, bolt_type_web, slot_length_web)

                        hole_match_matl_right.append(rl44)

                        if bar_wash == "Yes":

                            pt81 = pt41 + bm_list[bi].translate( -cos(dtor(sl)) * web_gap, sin(dtor(sl)) * web_gap, Shape(clip_size).thick + bw_thk)

                            pt82 = pt81 + bm_list[bi].translate( -(sin(dtor(sl)) * matl_length), -matl_length * cos(dtor(sl)), 0.0)

                            rp82 = bw_add(bm_list[bi], pt81, pt82, (180.0, 0.0, -90.0))

                            pl_holes(rp82)

                            hole_match_matl_right.append(rp82)

                    if holes_in_osl == "Yes":

                        clip_holes (rl44, ga_osl, bolt_size_OSL, hole_type_osl, 1, bolt_type_osl, 0)

                if which_side == "FS" or which_side == "BS":

                    pt51 = pt12 + bm_list[bi].translate( -(sin(dtor(sl)) * wp_to_corn), -wp_to_corn * cos(dtor(sl)), -web / 2)

                    pt52 = pt51 + bm_list[bi].translate( -(sin(dtor(sl)) * matl_length), -matl_length * cos(dtor(sl)), 0.0)

                    rl55 = clip_angle(bm_list[bi], pt52, pt51, (180.0, 0.0, 90.0))

                    if holes_in_web == "Yes":

                        hole55 = clip_holes (rl55, ga_web_leg, bolt_size, hole_type_web, 2, bolt_type_web, slot_length_web)

                        hole_match_matl_right.append(rl55)

                        if bar_wash == "Yes":

                            pt91 = pt51 + bm_list[bi].translate( -cos(dtor(sl)) * web_gap, sin(dtor(sl)) * web_gap, -(Shape(clip_size).thick + bw_thk))

                            pt92 = pt91 + bm_list[bi].translate( -(sin(dtor(sl)) * matl_length), -matl_length * cos(dtor(sl)), 0.0)

                            rp92 = bw_add(bm_list[bi], pt92, pt91, (0.0, 0.0, 90.0))

                            pl_holes(rp92)

                            hole_match_matl_right.append(rp92)

                    if holes_in_osl == "Yes":

                        clip_holes (rl55, ga_osl, bolt_size_OSL, hole_type_osl, 1, bolt_type_osl, 0)

        else:

            if which_end == "Right" or which_end == "Both":

                if which_side == "NS" or which_side == "BS":

                    pt21 = pt12 + bm_list[bi].translate( 0.0 - (sin(dtor(sl)) * wp_to_corn), -wp_to_corn * cos(dtor(sl)), web / 2)

                    pt22 = pt21 + bm_list[bi].translate( 0.0 - (sin(dtor(sl)) * matl_length), -matl_length * cos(dtor(sl)), 0.0)

                    rl22 = clip_angle(bm_list[bi], pt22, pt21, (0.0, 0.0, 90.0))

                    if holes_in_web == "Yes":

                        hole44 = clip_holes (rl22, ga_web_leg, bolt_size, hole_type_web, 2, bolt_type_web, slot_length_web)

                        hole_match_matl_right.append(rl22)

                        if bar_wash == "Yes":

                            pt61 = pt21 + bm_list[bi].translate( cos(dtor(sl)) * web_gap, -sin(dtor(sl)) * web_gap, Shape(clip_size).thick + bw_thk)

                            pt62 = pt61 + bm_list[bi].translate( -(sin(dtor(sl)) * matl_length), -matl_length * cos(dtor(sl)), 0.0)

                            rp62 = bw_add(bm_list[bi], pt62, pt61, (180.0, 0.0, 90.0))

                            pl_holes(rp62)

                            hole_match_matl_right.append(rp62)

                    if holes_in_osl == "Yes":

                        clip_holes (rl22, ga_osl, bolt_size_OSL, hole_type_osl, 1, bolt_type_osl, 0)

                if which_side == "FS" or which_side == "BS":

                    pt31 = pt12 + bm_list[bi].translate( -(sin(dtor(sl)) * wp_to_corn), -wp_to_corn * cos(dtor(sl)), -web / 2)

                    pt32 = pt31 + bm_list[bi].translate( -(sin(dtor(sl)) * matl_length), -matl_length * cos(dtor(sl)), 0.0)

                    rl33 = clip_angle(bm_list[bi], pt31, pt32, (180.0, 0.0, -90.0))

                    if holes_in_web == "Yes":

                        hole55 = clip_holes (rl33, ga_web_leg, bolt_size, hole_type_web, 2, bolt_type_web, slot_length_web)

                        hole_match_matl_right.append (rl33)

                        if bar_wash == "Yes":

                            pt71 = pt31 + bm_list[bi].translate( cos(dtor(sl)) * web_gap, -sin(dtor(sl)) * web_gap, -(Shape(clip_size).thick + bw_thk))

                            pt72 = pt71 + bm_list[bi].translate( -(sin(dtor(sl)) * matl_length), -matl_length * cos(dtor(sl)), 0.0)

                            rp72 = bw_add(bm_list[bi], pt71, pt72, (0.0, 0.0, -90.0))

                            pl_holes(rp72)

                            hole_match_matl_right.append(rp72)

                    if holes_in_osl == "Yes":

                        clip_holes (rl33, ga_osl, bolt_size_OSL, hole_type_osl, 1, bolt_type_osl, 0)

            if which_end == "Left" or which_end == "Both":

                if which_side == "NS" or which_side == "BS":

                    pt41 = pt11 + bm_list[bi].translate( -(sin(dtor(sl)) * wp_to_corn), -wp_to_corn * cos(dtor(sl)), web / 2)

                    pt42 = pt41 + bm_list[bi].translate( -(sin(dtor(sl)) * matl_length), -matl_length * cos(dtor(sl)), 0.0)

                    rl44 = clip_angle(bm_list[bi], pt41, pt42, (0.0, 0.0, -90.0))

                    if holes_in_web == "Yes":

                        hole22 = clip_holes (rl44, ga_web_leg, bolt_size, hole_type_web, 2, bolt_type_web, slot_length_web)

                        hole_match_matl_left.append(rl44)

                        if bar_wash == "Yes":

                            pt81 = pt41 + bm_list[bi].translate( -cos(dtor(sl)) * web_gap, sin(dtor(sl)) * web_gap, Shape(clip_size).thick + bw_thk)

                            pt82 = pt81 + bm_list[bi].translate( -(sin(dtor(sl)) * matl_length), -matl_length * cos(dtor(sl)), 0.0)

                            rp82 = bw_add(bm_list[bi], pt81, pt82, (180.0, 0.0, -90.0))

                            pl_holes(rp82)

                            hole_match_matl_left.append(rp82)

                    if holes_in_osl == "Yes":

                        clip_holes (rl44, ga_osl, bolt_size_OSL, hole_type_osl, 1, bolt_type_osl, 0)

                if which_side == "FS" or which_side == "BS":

                    pt51 = pt11 + bm_list[bi].translate( -(sin(dtor(sl)) * wp_to_corn), -wp_to_corn * cos(dtor(sl)), -web / 2)

                    pt52 = pt51 + bm_list[bi].translate( -(sin(dtor(sl)) * matl_length), -matl_length * cos(dtor(sl)), 0.0)

                    rl55 = clip_angle(bm_list[bi], pt52, pt51, (180.0, 0.0, 90.0))

                    if holes_in_web == "Yes":

                        hole33 = clip_holes (rl55, ga_web_leg, bolt_size, hole_type_web, 2, bolt_type_web, slot_length_web)

                        hole_match_matl_left.append(rl55)

                        if bar_wash == "Yes":

                            pt91 = pt51 + bm_list[bi].translate( -cos(dtor(sl)) * web_gap, sin(dtor(sl)) * web_gap, -(Shape(clip_size).thick + bw_thk))

                            pt92 = pt91 + bm_list[bi].translate( -(sin(dtor(sl)) * matl_length), -matl_length * cos(dtor(sl)), 0.0)

                            rp92 = bw_add(bm_list[bi], pt92, pt91, (0.0, 0.0, 90.0))

                            pl_holes(rp92)

                            hole_match_matl_left.append(rp92)

                    if holes_in_osl == "Yes":

                        clip_holes (rl55, ga_osl, bolt_size_OSL, hole_type_osl, 1, bolt_type_osl, 0)

        if hls_and_blts == "Add holes only" or hls_and_blts == "Add holes and bolts":

            if which_end == "Left" or which_end == "Both":

                if which_side == "NS" or which_side == "BS":

                    match_holes_bolts(bm_list[bi], hole22, hole_match_matl_left)

                else:

                    match_holes_bolts(bm_list[bi], hole33, hole_match_matl_left)

            if which_end == "Right" or which_end == "Both":

                if which_side == "NS" or which_side == "BS":

                    match_holes_bolts(bm_list[bi], hole44, hole_match_matl_right)

                else:

                    match_holes_bolts(bm_list[bi], hole55, hole_match_matl_right)

## End script #########################################################################################################################################