##  Col_SafetyHoles.py Version 1.10

##  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 safety cable holes to WF columns.

    Select columns to add holes to and beams or joists to establish reference points.

    A dialog box will come up for each column selected. The script will attempt to add a hole pattern

    for each beam selected in the columns using the values set in the dialog box. If the holes fall off

    the column or if the script attempts to add a hole where one exists, the script will not error out.

    Flange gage will default each loop to value in material file, but can be overridden in the dialog box.

    Web gage defaults are based upon column depth and are calculated by function ret_web_ga(mem).

    Go to function definition ret_web_ga(mem) to change the default web gages.

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

 

    The dialog box may not fit on a screen display with a resolution of 1024x768 or less. We suggest disabling the dialog

    box image for those resolutions.

 

    An option to add the same hole patterns to all members with the same mark has not been implemented in this script.

 

    R3 (11/7/01)    -           Corrected error in Dialog for flange gage. Default was web_ga - should be flg_ga.

    R4 (9/24/02)    -           Added ability to pick multiple columns and beams. Created functions to return

                                web gage and hole pattern work point. Each column gets a dialog box.

    R5 (3/6/03)     -           Add try statement to hole pattern function. The script will no longer error out

                                if a pattern falls off the end of a selected column.

    R6 (11/20/03)   -           Edited code to work with SDS/2 6.323

                                Version 6.323 expects the reference point to be translated to the face of the flange.

                                Previously the reference point at the column centerline was the argument given to the hole pattern function.

    V7R2 (4/20/05)  -           Add the following:

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

                                ClearSelection()

    Version 1.03 (4/9/06) -     Remove support for SDS/2 6.3xx

                                Rework dialog box - tabs and add image

                                Add import/export defaults feature

    Version 1.04 (4/15/06) -    Remove "Face D" from dlg1.checkbutton default tuple

                                Consolidate if statements in hole pattern function

    Version 1.05 (9/12/06) -    Update function ret_web_ga

    Version 1.06 (9/18/06) -    Sort default file by variable name

                                Add hole_add.error at except statement in def safety_hole(), import param and hole_add

    Version 1.07 (10/30/06) -   Import modules

                                Use 'os.getcwd()' to determine the current working directory.

                                The current working directory should be the SDS/2 data root directory.

                                Create function to run script - all variables are local - delete from

                                    global namespace upon exit

                                Add option in dialog box to print documentation only

                                Add formatExceptionInfo function

    Version 1.08 (11/27/06) -   Eliminate imports string and types

    Version 1.09 (4/6/07) -     Add option to use fabricator preferred gages instead of 3 1/2" and 5 1/2"

                                Incorporate function mem_select

                                Modify while loops

                                Option in Defaults section to always use material file gage for 8" wide flanges

    Version 1.10 (10/3/07) -    Add ClearSelection in try/finally block

                                Move imports out of run_script()

    Version 2.00 (12/15/07) -   Highlight/unhighlight members by adding to and removing from selection set with

                                SelectionAdd() and SelectionRemove() respectively.

                                Select members with memAreaSelect()

                                Replace break with return

                                Replace 'if variable is None' with 'if not variable'

   

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

    ###### THIS VERSION WILL NOT WORK IN SDS/2 VERSIONS PRIOR TO 7.105 ######

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

                       

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

    Developed in SDS/2 6.245, Python 2.2.1, 3/6/03 (R5)

    Tested in SDS/2 6.310

    Tested in SDS/2 7.002 (8/11/04)

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

    For comments, suggestions or questions call BV at the number above, email bvaughan@bvdetailing or post to SDS/2 forum.

"""

 

# startup code begin

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

from param import SelectionAdd, SelectionRemove, SelectionToggle

from member import Member, MemberLocate

from point import Point, PointLocate

from macrolib.FileDefaults import import_data, export_data

from macrolib.angle import rtod, dtor

from macrolib.ExceptWarn import formatExceptionInfo

from macrolib.L3D import LineLineIntersect3D, ret_WP

from macrolib.MemSelection import memAreaSelect

 

import os

import sys

Units("feet")

from hole_add import Hole

from job import Job

from fab import Fabricator

# startup code end

 

def run_script():

    try:

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

        drv_letter, drv_path = os.path.splitdrive(os.getcwd())

        ## Variables section

        # system path for defaults file

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

        # defaults file

        def_file = "Col_SafetyHoles_v1_08.txt"   # defaults file

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

        # ("Enable", "Disable") to/from 'def_file'

        enable_default_import_export = "Enable"

       

        script_name = "Col_SafetyHoles_v1.09.py"

 

        # Dialog box image path and file name

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

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

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

        

        ## Defaults section

        # distance from floor to cable holes

        dist_first = 21.0

        # vertical distance center to center of cable holes

        dist_cc = 21.0

 

        # "Yes", "No"       

        add_lifeline_holes = "No"

        # "Yes", "No"

        add_safety_holes = "Yes"

        # distance to lifeline hole above finished floor

        dist_lifeline_hole = 90.0

 

        # floor thickness       

        floor_thk = 6.5

        # hole size

        hole_size = 0.8125

 

        # pattern type web "Both Ga Lines" "Left Ga Line" "Right Ga Line" "On CL"

        patt_type_web = "On CL"

        # pattern type flange A "Both Ga Lines" "FS Ga Line" "NS Ga Line"

        patt_type_flg_a = "NS Ga Line"

        # pattern type flange C "Both Ga Lines" "FS Ga Line" "NS Ga Line"

        patt_type_flg_c = "NS Ga Line"

        # column faces to add safety holes ["Face A", "Face B", "Face C"]

        col_face_list = ["Face B"]

 

        # 'Yes', 'No' use fabricator gages for defaults if 'Yes'

        use_fab_gage = 'Yes'

        # 'Yes', 'No' - Option to always use material file gage for column flanges < 8.3" wide

        use_mtrl_ga_8_flg = 'Yes'

        ## END VARIABLES AND DEFAULTS SECTIONS ################################

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

        ## Function definitions ###############################################

        # Return web gage of column as a function of the column depth

        def ret_web_ga(mem):

            if mem.nom_depth <= 6.0:

                web_ga = 3.0

            elif mem.nom_depth <= 10.0:

                web_ga = 4.0

            else:

                web_ga = 6.0

            return web_ga

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

        # hole pattern add function

        def safety_hole (mem, hl_ref_pt, x_off, y_off, c_c, hs, patt_type, no_cols, col_face):

            if col_face == "Face B":

                hl_face = "Web NS"

                if patt_type == "Both Ga Lines":

                    hl_patt = "Center Right"

                elif patt_type == "On CL":

                    hl_patt = "Above Right"

                    y_off = 0.0

                elif patt_type == "Left Ga Line":

                    hl_patt = "Above Right"

                elif patt_type == "Right Ga Line":

                    hl_patt = "Below Right"

                else:

                    print "Something is wrong with Face B pattern"

            if col_face == "Face A":

                hl_face = "Top Face"

                if patt_type == "Both Ga Lines":

                    hl_patt = "Center Right"

                elif patt_type == "FS Ga Line":

                    hl_patt = "Above Right"

                elif patt_type == "NS Ga Line":

                    hl_patt = "Below Right"

                else:

                    print "Something is wrong with Face A pattern"

            if col_face == "Face C":

                hl_face = "Bottom Face"

                if patt_type == "Both Ga Lines":

                    hl_patt = "Center Right"

                elif patt_type == "FS Ga Line":

                    hl_patt = "Below Right"

                elif patt_type == "NS Ga Line":

                    hl_patt = "Above Right"

                else:

                    print "Something is wrong with Face C pattern"

            try:

            # hole group add begin

                hole26 = Hole()

                hole26.mtrl = [mem, ]

                hole26.pt1 = hl_ref_pt

                hole26.hole_type = "Standard Round"

                hole26.face = hl_face

                hole26.valid_cnc = "Yes"

                hole26.x_ref_offset = x_off

                hole26.y_ref_offset = y_off

                hole26.x_spa = c_c

                hole26.y_spa = 0.0

                hole26.group_rot = 0.0

                hole26.locate = hl_patt

                hole26.columns = no_cols

                hole26.rows = 1

                hole26.bolt_type = "Auto"

                hole26.bolt_dia = hs - 0.0625

                hole26.slot_rot = 0.0

                hole26.length = hole26.calc_slot_length()

                hole26.hole_dia = hole26.calc_hole_size()

                hole26.show_window = "Yes"

                hole26.create()

            except hole_add.error, e:

                # param.yes_or_no ('%s\n%s' % ("Hole add error", e.args[0]), "Okay")

                pass

            # hole group add end

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

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

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

        ## import defaults data 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:

 

            col_list = memAreaSelect("Select WF Column members to receive holes or RETURN.", \

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

            if not col_list:

                return

            mem1 = col_list[0]

 

            bm_list = memAreaSelect("Select Beam or Joist members for reference elevation.", \

                                    ['Beam', 'Joist'], ['All', ])

            if not bm_list:

                Warning("You did not pick any beams. Exiting script.")

                return

            mem2 = bm_list[0]

            # Clear highlighting of selected beam members

            ClearSelection()

           

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

            # begin loop for columns

            for ci, column in enumerate(col_list):

                SelectionAdd(column)

                # Create reference point list

                pt_list = []

                for beam in bm_list:

                    list1 = ret_WP(column, beam)

                    pt_list.append(list1[0])

               

                # calculate flange and web gages for dialog box

                if use_fab_gage == 'Yes':

                    if column.gage >= 5.0:

                        if use_mtrl_ga_8_flg == 'Yes' and column.bf < 8.3:

                            flg_ga = column.gage

                        else:

                            flg_ga = Fabricator().clip_ang_wide_gage

                    else:

                        flg_ga = Fabricator().clip_ang_narrow_gage

                else:                   

                    flg_ga = column.gage

                   

                web_ga = ret_web_ga(column)

               

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

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

                dlg1 = Dialog("Add safety cable holes to column #%s of %s" % (ci+1, len(col_list)))

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

                dlg1.tabset_begin()

                dlg1.tab("Safety Cable Hole information")

                dlg1.column_group_begin()

                dlg1.column(0)

                dlg1.group_title("General Information")

                dlg1.menu("add_safety_holes", ("Yes", "No"), add_safety_holes, "Add safety cable holes")

                dlg1.menu("add_lifeline_holes", ("Yes", "No"), add_lifeline_holes, "Add lifeline holes")

                dlg1.group_title_end

 

                # checkbutton automatically is formatted as a group title       

                dlg1.checkbutton("col_face_list", ["Face A", "Face B", "Face C"], col_face_list, "Column Face Selection")

 

                dlg1.group_title("Column Information")

                dlg1.line("Selected Column Size: %s        Piecemark: %s" % (column.size, column.piecemark))

                dlg1.line("Plan Rotation: " + "%0.4f      Location: %s, %s, %s" % (column.plan_rotation,\

                                                                                   dim_print(column.left_location.x),\

                                                                                   dim_print(column.left_location.y),\

                                                                                   dim_print(column.left_location.z)))

                dlg1.group_title_end

 

                dlg1.group_title("Column Gages")               

                if use_fab_gage == 'Yes':

                    dlg1.label(dim_print(column.gage), "Column flange gage read from material file  ")

                    if use_mtrl_ga_8_flg == 'Yes' and column.bf < 8.3:

                        dlg1.line("Since column.bf < 8.3, the default column flage gage is read from the material file.")

                    else:

                        dlg1.line("The default column flage gage is read from Fabricator setup.")

                else:                

                    dlg1.label(dim_print(Fabricator().clip_ang_wide_gage), "Fabricator standard wide gage  ")

                    dlg1.label(dim_print(Fabricator().clip_ang_narrow_gage), "Fabricator standard narrow gage")

                    dlg1.line("The default column flage gage is read from the material file.")

                dlg1.line("The default column web gage is a function of the column depth.")

                dlg1.entry("flg_ga", dim_print(flg_ga), "Column FLANGE Gage")

                dlg1.entry("web_ga", dim_print(web_ga), "Column WEB Gage")       

                dlg1.group_title_end

               

                dlg1.column(0)

                dlg1.image(image_name1)

               

                dlg1.tab("Hole Pattern Information")

                dlg1.group_title("Hole diameter for safety cable holes")

                dlg1.entry("hole_size", dim_print(hole_size), "Hole diameter                              ")

                dlg1.group_title_end

                

                dlg1.group_title("Safety Cable Vertical Locations")

                dlg1.entry("floor_thk", dim_print(floor_thk), "Floor thickness                         ")

                dlg1.entry("dist_first", dim_print(dist_first), "Dist from floor to 1st safety cable")

                dlg1.entry("dist_cc", dim_print(dist_cc), "C/C dist between safety cables")

                dlg1.entry("dist_lifeline_hole", dim_print(dist_lifeline_hole), "Dist from floor to lifeline")

                dlg1.group_title_end

               

                dlg1.group_title("Hole Pattern Options")

                dlg1.menu("patt_type_flg_a", ("Both Ga Lines", "FS Ga Line", "NS Ga Line"), patt_type_flg_a, "Pattern type flange A")

                dlg1.menu("patt_type_web", ("Both Ga Lines", "Left Ga Line", "Right Ga Line", "On CL"), patt_type_web, "Pattern type web, Face B")

                dlg1.menu("patt_type_flg_c", ("Both Ga Lines", "FS Ga Line", "NS Ga Line"), patt_type_flg_c, "Pattern type flange C")

                dlg1.group_title_end

 

                dlg1.tab("Graphic Image")

                dlg1.image(image_name)

                dlg1.tabset_end()

                try:

                    dd1 = dlg1.done()

                except ResponseNotOK:

                    return

               

                # Update the local namespace

                for key, value in dd1.items():

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

                   

                if col_face_list == None:

                    col_face_list = []

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

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

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

                if print_doc == "Yes":

                    print __doc__

                    return

 

                # Export defaults to disk if enabled

                if enable_default_import_export == "Enable":

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

 

                SelectionRemove(column)                   

                   

                # Loop on point list, Add hole patterns

                for pt in pt_list:

                    if "Face A" in col_face_list:

                        if add_safety_holes == "Yes":                   

                            safety_hole(column, pt + column.translate(0.0, column.depth/2, 0.0), \

                                        dist_first + floor_thk, flg_ga / 2, dist_cc, hole_size, patt_type_flg_a, 2, "Face A")

                        if add_lifeline_holes == "Yes":

                            safety_hole(column, pt + column.translate(0.0, column.depth/2, 0.0), \

                                        dist_lifeline_hole + floor_thk, flg_ga / 2, dist_cc, hole_size, patt_type_flg_a, 1, "Face A")

                           

                    if "Face B" in col_face_list:

                        if add_safety_holes == "Yes":

                            safety_hole(column, pt, dist_first + floor_thk, web_ga / 2, dist_cc, hole_size, \

                                        patt_type_web, 2, "Face B")

                        if add_lifeline_holes == "Yes":

                            safety_hole(column, pt, dist_lifeline_hole + floor_thk, web_ga / 2, dist_cc, hole_size, \

                                        patt_type_web, 1, "Face B")

                           

                    if "Face C" in col_face_list:

                        if add_safety_holes == "Yes":

                            safety_hole(column, pt + column.translate(0.0, -column.depth/2, 0.0), \

                                        dist_first + floor_thk, flg_ga / 2, dist_cc, hole_size, patt_type_flg_c, 2, "Face C")

                        if add_lifeline_holes == "Yes":

                            safety_hole(column, pt + column.translate(0.0, -column.depth/2, 0.0), \

                                        dist_lifeline_hole + floor_thk, flg_ga / 2, dist_cc, hole_size, patt_type_flg_c, 1, "Face C")

                           

            if not yes_or_no("Add additional safety cable holes to WF columns?"):

                return

    except:

        Warning(formatExceptionInfo())

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

if __name__ == '__main__':

    try:

        run_script()

    finally:

        ClearSelection()

        del run_script