Back to SDS/2 Parametric Scripts

 

 

 

 

 

 

 

 

##  Beam_NailerHoles.py Version 1.07

##  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 nailer holes to WF beam flanges and web.

 

    Flange gage is obtained from the material file.

 

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

 

    R3 -    Add options for Top Flange, Bottom Flange, or Both Flages - staggered or non-staggered

            If non-staggered - NS, FS, or BS

    R4 -    Add options for hole type and bolt type

 

    Version 1.02 (2/16/06) -    Add ClearSelection()

    Version 1.03 (3/16/06) -    Add import/export defaults feature

                                Remove support for SDS/2 Version 6.3

                                Add holes in web

                                Add support for short beams

    Version 1.04 (3/17/06) -    Add error handling function

                                Pass hole add function if cols_ns and cols_fs = 0

    Version 1.05 (5/9/06) -     Add support for channel material. Flange holes may not work properly.

    Version 1.06 (12/13/06) -   Add beam gage in dialog box. Defaults to gage in material file.

    Version 1.07 (1/25/07) -    Change location of image and default files

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

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

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

 

    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 in SDS/2 6.327, Python 2.2.1, 4/6/04 (R2)

 

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

    Mark Karpinsky, New Jersey Iron, Inc.

    For comments, suggestions or questions call BVD at the number above or email bvaughan@bvdetailing.com

 

    Go to Defaults section to modify defaults.

"""

# startup code begin

import sys

import traceback

from param import *

from math import *

Units("feet")

saved_sds2_version = '7.002'

saved_python_version = (2, 1, 1, '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

 

import os

# startup code end

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

## Variables section

# system path for defaults file

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

 

# defaults file name

def_file = "Beam_NailerHoles.txt"

 

# Path to image files and file names

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

image_name = os.path.join(image_path, "C:/ParamImg/Beam_NailerHoles.gif")

image_name1 = os.path.join(image_path, "C:/ParamImg/Beam_NailerHoles1.gif")

image_name2 = os.path.join(image_path, "C:/ParamImg/Beam_NailerHoles2.gif")

 

script_name = "Beam_NailerHoles_v1.07.py"

 

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

enable_default_import_export = "Enable"

 

## Defaults section

min_dist_left = "6"                 # default minimum distance from left end of material

min_dist_right = "6"                # default minimum distance from right end of material

bolt_size = "1/2"                     # default bolt size

hole_type = "Standard Round"        # "Standard Round", "Oversized Round", "Plug Weld Hole"

type_bolt = "A325N"                  # type of bolt Job().bolt_sched()

nailer_spacing = "32"               # default nailer hole spacing

beam_face_list = ["Top Flange"]     # "Top Flange", "Bottom Flange", "Both Flanges", "Web"

stagger_yes_or_no = "Staggered"     # "Staggered", "Not Staggered"

which_side = "BS"                   # "NS", "FS", "BS"

# Defaults for web holes

dist_first = "3"

vert_spa = "6"

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

## Function definition section

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 min_dist_left, min_dist_right, bolt_size, nailer_spacing, dist_first, vert_spa

    min_dist_left = dim_print(dim(min_dist_left))

    min_dist_right = dim_print(dim(min_dist_right))

    bolt_size = dim_print(dim(bolt_size))

    nailer_spacing = dim_print(dim(nailer_spacing))

    dist_first = dim_print(dim(dist_first))

    vert_spa = dim_print(dim(vert_spa))

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

## Function definitions for saving default values to disk

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

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

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

# begin definition of hole pattern add function

def nailer_hole (mem, hl_ref_pt, x_off, y_off, c_c, ht, bd, bt, patt_type, no_cols, no_rows, which_flg, v_spa):

    try:

        hole26 = Hole()

        hole26.mtrl = [mem, ]

        hole26.pt1 = hl_ref_pt

        hole26.hole_type = ht

        hole26.face = which_flg

        hole26.valid_cnc = "Yes"

        hole26.x_ref_offset = x_off

        hole26.y_ref_offset = y_off

        hole26.x_spa = c_c

        hole26.y_spa = v_spa

        hole26.group_rot = 0.0

        hole26.locate = patt_type

        hole26.columns = no_cols

        hole26.rows = no_rows

        hole26.bolt_type = bt

        hole26.bolt_dia = bd

        hole26.slot_rot = 0.0

        hole26.length = hole26.calc_slot_length()

        hole26.hole_dia = hole26.calc_hole_size()

        hole26.show_window = "Yes"

        hole26.create()

        # hole group add end

    except:

        yes_or_no("Error ading holes.\n" + formatExceptionInfo(), "OK")

# end function definition

# 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

# end function definition

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

# a exception handler function to format the exception info into a string for dialog display -  credit Phil Adams [padams@colloquiuminc.com]

def formatExceptionInfo(maxTBlevel=5):

      cla, exc, trbk = sys.exc_info()

      excName = cla.__name__

      try:

            excArgs = exc.__dict__["args"]

      except KeyError:

            excArgs = "<none>"

      excTb = traceback.format_tb(trbk, maxTBlevel)

      #- build the return string ready to be displayed

      _str = "Error: " + excName + "\nDesc: "

      for i in range(len(excArgs)):

            _str = _str + excArgs[i] + "\n"

      #for ii in range(len(excTb)):

      _str = _str + excTb.pop() # + "\n"

      return _str

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

## 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(default_file_path, def_file)))

    except:

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

    if beam_face_list == None:

        beam_face_list = "['Top Flange']"

    try:

        beam_face_list = eval(beam_face_list)

    except:

        beam_face_list = ['Top Flange']

## Main program loop

while 1:

    ClearSelection()

    z = 1

    bm_list = []

    while z:

        mem1 = MemberLocate("Select WF or Std BEAM Member to Add Nailer Holes")

        if mem1 == None:

            break

        else:

            if mem1.type == "Beam":

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

                    z = 0

                else:

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

            else:

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

    if mem1 == None:

        break

    else:

        bm_list.append(mem1)

    chk_mem_list = member_count(bm_list[0])

    if len(chk_mem_list) > 1:

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

            bm_list = chk_mem_list

    form_script_variables()

    flg_gage = bm_list[0].gage

    ## DIALOG BOX 1 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    dlg1 = Dialog( "Add Nailer Holes to WF Beams" )

    dlg1.tabset_begin()

    dlg1.tab("General Information")

    dlg1.column_group_begin()

    dlg1.column(0)

    dlg1.checkbutton("beam_face_list", ["Top Flange", "Bottom Flange", "Both Flanges", "Web"], beam_face_list, "Select Flange(s) or Web")

    dlg1.group_title("Nailer hole pattern options")

    dlg1.menu("stagger_yes_or_no", ("Staggered", "Not Staggered"), stagger_yes_or_no, "Staggered or Not Staggered")

    dlg1.entry("nailer_spacing", nailer_spacing, "Nailer Hole Spacing")

    dlg1.entry("min_dist_left", min_dist_left, "Minimum Distance Left End")

    dlg1.entry("min_dist_right", min_dist_right, "Minimum Distance Right End")

    dlg1.group_title_end

    dlg1.column(0)

    dlg1.group_title("Bolt/Hole Information")

    dlg1.entry("flg_gage", dim_print(flg_gage), "Flange gage")

    dlg1.entry("bolt_size", bolt_size, "Bolt Size")

    dlg1.menu("hole_type", ("Standard Round", "Oversized Round", "Plug Weld Hole"), hole_type, "Hole type")

    dlg1.menu("type_bolt", Job().bolt_sched(), type_bolt, "Bolt type")

    dlg1.group_title_end

    dlg1.group_title("Not Staggered Option for Flanges")

    dlg1.menu("which_side", ("NS", "FS", "BS"), which_side, "Which Side")

    dlg1.group_title_end

    dlg1.group_title("Web Hole Options")

    dlg1.entry("dist_first", dist_first, "Distance to first row")

    dlg1.entry("vert_spa", vert_spa, "Row spacing")

    dlg1.column_group_end()

    dlg1.image(image_name1)

    dlg1.column_group_end()

    dlg1.tab("Graphic Image")

    dlg1.image(image_name)

    dlg1.line("Illustration of the basic variables for adding nailer holes in the flanges and web of beam members")

    dlg1.tab("Short Beam Image")

    dlg1.group_title("Pairs of holes each end will be added to short beams")

    dlg1.image(image_name2)

    dlg1.group_title_end

    dlg1.tabset_end()

    try:

        dd1 = dlg1.done()

    except ResponseNotOK:

        break

    globals().update(dd1)

    try:

        beam_face_list = dd1['beam_face_list']

    except KeyError:

        beam_face_list = []

    ## END DIALOG BOX 1 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    # save defaults to disk for the next time

    if enable_default_import_export == "Enable":

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

    matl_length = bm_list[0].input_length - bm_list[0].left.setback - bm_list[0].right.setback

    allow_out_to_out = matl_length - min_dist_left - min_dist_right

    no_spa = int(floor(allow_out_to_out / nailer_spacing))

    dist_left = min_dist_left + (allow_out_to_out/2) - (no_spa*nailer_spacing/2.0)

    if allow_out_to_out <= nailer_spacing:

        short_beam = "Yes"

        if allow_out_to_out <= nailer_spacing:

            dimen_out_to_out = allow_out_to_out

        else:

            dimen_out_to_out = nailer_spacing

        dist_left = min_dist_left

    else:

        short_beam = "No"

        dimen_out_to_out = no_spa*nailer_spacing

    if stagger_yes_or_no == "Staggered":

        if no_spa/2 == float(no_spa)/2:

            cols_ns = int(float(no_spa)/2-1)

            cols_fs = int(float(no_spa)/2)

        else:

            cols_ns = int(float(no_spa)/2)

            cols_fs = int(float(no_spa)/2)

        for bi in range(len(bm_list)):

            ref_WP = bm_list[bi].left_location + bm_list[bi].translate(bm_list[bi].left.setback, 0.0, 0.0)

            if "Top Flange" in beam_face_list or "Both Flanges" in beam_face_list:

                nailer_hole(bm_list[bi], ref_WP, dist_left, flg_gage/2, dimen_out_to_out, hole_type,\

                            bolt_size, type_bolt, "Center Right", 2, 1, 1, 0.0)

                if short_beam == "No":

                    if cols_ns > 0:

                        nailer_hole(bm_list[bi], ref_WP, dist_left+nailer_spacing*2, flg_gage/2, nailer_spacing*2, hole_type,\

                                    bolt_size, type_bolt, "Below Right", cols_ns, 1, 1, 0.0)

                    if cols_fs > 0:

                        nailer_hole(bm_list[bi], ref_WP, dist_left + nailer_spacing, flg_gage/2, nailer_spacing*2, hole_type,\

                                    bolt_size, type_bolt, "Above Right", cols_fs, 1, 1, 0.0)

            if "Bottom Flange" in beam_face_list or "Both Flanges" in beam_face_list:

                nailer_hole(bm_list[bi], ref_WP, dist_left, flg_gage/2, dimen_out_to_out, hole_type,\

                            bolt_size, type_bolt, "Center Right", 2, 1, 3, 0.0)

                if short_beam == "No":

                    if cols_ns > 0:

                        nailer_hole(bm_list[bi], ref_WP, dist_left+nailer_spacing*2, flg_gage/2, nailer_spacing*2, hole_type,\

                                    bolt_size, type_bolt, "Below Right", cols_ns, 1, 3, 0.0)

                    if cols_fs > 0:

                        nailer_hole(bm_list[bi], ref_WP, dist_left + nailer_spacing, flg_gage/2, nailer_spacing*2, hole_type,\

                                    bolt_size, type_bolt, "Above Right", cols_fs, 1, 3, 0.0)

            if "Web" in beam_face_list:

                nailer_hole(bm_list[bi], ref_WP, dist_left, dist_first, dimen_out_to_out, hole_type,\

                            bolt_size, type_bolt, "Below Right", 2, 2, 2, vert_spa)

                if short_beam == "No":

                    if cols_ns > 0:

                        nailer_hole(bm_list[bi], ref_WP, dist_left+nailer_spacing*2, dist_first, nailer_spacing*2, hole_type,\

                                    bolt_size, type_bolt, "Below Right", cols_ns, 1, 2, 0.0)

                    if cols_fs > 0:

                        nailer_hole(bm_list[bi], ref_WP, dist_left+nailer_spacing, dist_first+vert_spa, nailer_spacing*2, hole_type,\

                                    bolt_size, type_bolt, "Below Right", cols_fs, 1, 2, 0.0)

    else:

        for bi in range(len(bm_list)):

            ref_WP = bm_list[bi].left_location + bm_list[bi].translate(bm_list[bi].left.setback, 0.0, 0.0)

            if which_side == "NS":

                hl_patt_ref = "Below Right"

            elif which_side == "FS":

                hl_patt_ref = "Above Right"

            else:

                hl_patt_ref = "Center Right"

            if short_beam == "No":

                if "Top Flange" in beam_face_list or "Both Flanges" in beam_face_list:

                    nailer_hole(bm_list[bi], ref_WP, dist_left, flg_gage/2, nailer_spacing, hole_type,\

                                bolt_size, type_bolt, hl_patt_ref, no_spa + 1, 1, 1, 0.0)

                if "Bottom Flange" in beam_face_list or "Both Flanges" in beam_face_list:

                    nailer_hole(bm_list[bi], ref_WP, dist_left, -flg_gage/2, nailer_spacing, hole_type,\

                                bolt_size, type_bolt, hl_patt_ref, no_spa + 1, 1, 3, 0.0)

                if "Web" in beam_face_list:

                    nailer_hole(bm_list[bi], ref_WP, dist_left, dist_first, nailer_spacing, hole_type,\

                                bolt_size, type_bolt, hl_patt_ref, no_spa + 1, 2, 2, vert_spa)

            else:

                if "Top Flange" in beam_face_list or "Both Flanges" in beam_face_list:

                    nailer_hole(bm_list[bi], ref_WP, dist_left, flg_gage/2, allow_out_to_out, hole_type,\

                                bolt_size, type_bolt, hl_patt_ref, 2, 1, 1, 0.0)

                if "Bottom Flange" in beam_face_list or "Both Flanges" in beam_face_list:

                    nailer_hole(bm_list[bi], ref_WP, dist_left, -flg_gage/2, allow_out_to_out, hole_type,\

                                bolt_size, type_bolt, "Below Right", 2, 1, 3, 0.0)

                if "Web" in beam_face_list:

                    nailer_hole(bm_list[bi], ref_WP, dist_left, dist_first, allow_out_to_out, hole_type,\

                                bolt_size, type_bolt, "Below Right", 2, 2, 2, vert_spa)

    Add_nailer = yes_or_no("Add nailer holes to another WF beam")

    if Add_nailer == 0:

        break

# xxxxxxxxxxxxxxxxxxxxxxxxxxxx end script xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx