## StitchPlate.py Version 1.01

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

## All rights reserved

## NOT FOR SALE

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

'''

#   Add bolted or welded  stitch plates to a vertical or horizontal brace

#   member for members with material NS & FS. Brace member can be positioned

#   on neutral axis or not.

#   Initial release 7/20/04 (R1)

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

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

#   Developed in SDS2 6.329

#

#   Developed by Bruce Vaughan, BV Detailing & Design, Inc.

#   For comments, suggestions or questions call BVD at (615) 646-9239, email

#   at bvdet@comcast.net, or post to the Detailing Forum at sds2.com

#

#   Version History:

#   Version 1.00 (11/2/07) -

#       Update code for SDS/2 7.107 and 7.110

#   Version 1.01 (11/3/07) -

#       Add support for bolted and welded stitches on bracing positioned on

#       neutral axis. Read gage of angle from material file. Add support for

#       bracing with mem.angle_leg_up == 'Yes'

#

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

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

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

'''

 

# startup code begin

import os

import sys

from math import ceil

 

from param import yes_or_no, ResponseNotOK, Units, ClearSelection, Dialog

from param import dim_print, Warning, dim

from param import SelectionRemove, SelectionToggle

Units("feet")

from shape import Shape

from point import Point, PointLocate

from member import Member, MemberLocate, MemberAllocated

from rect_plate import RectPlate

from weld_add import Weld

from job import Job

from fab import Fabricator

from hole_add import Hole

 

from macrolib.FileDefaults import import_data, export_data

# from macrolib.Weld import mtrl_weld

from macrolib.MemSelection import mem_select, memAreaSelect

from macrolib.material_list1 import iter_mtrl, list_mtrl

from macrolib.bolt_match import bolt_match, hole_match

 

# startup code end

def run_script():

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

    ## Variables section

    # small number

    eps = 0.000001

    # system path for defaults file

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

    # defaults file

    def_file = "BoltedStitch.txt"

    # image files

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

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

   

    script_name = "BoltedStitch_v1.00.py"

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

    enable_default_import_export = "Enable"

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

    gradeList = Job().steel_grades("Plate").keys()

    holetypeList = ["Standard Round", "Oversized Round"]

    bolttypeList = Job().bolt_sched()

   

    ## Defaults section

    # stitch type

    stitch_type = "Bolted"

    # maximum stitch spacing

    max_stitch_spacing = 72.0

    # minumum number of stitches

    min_no_stitch = 2

    # stitch finish

    pl_color = "Yellow Zinc"

    # steel grade

    steelgrade = "A36"

    # the default stitch plate thickness is determined by the thickness

    # of plates found on the member

    # initialize bltd_thk in case no plate material is found

    bltd_thk = 0.375

    wldd_thk = 0.375

    # stitch width

    bltd_width = 2.5

    # projection of welded stitch

    wldd_width = 0.5

    # stitch length

    bltd_length = 2.5

    wldd_length = 2.5

    # length from end of member to inner attachment

    weld_length = 12.0

   

    # dist_between_attach - calculated using WP to WP,

    # matl_setback, obj.edge_dist_vbrc, and # bolts

    # default number of bolts in end connection

    no_bolts = 4.0

    # bolt spacing

    bolt_spa = 3.0

    # bolt diameter for stitches

    stitch_bolt_size = 0.75

    # hole type

    stitch_hole_type = "Standard Round"

    # bolt type

    stitch_bolt_type = "A325N"

    ## END DEFAULTS SECTION

    ## MACRO FUNCTIONS ###########################################

    # add stitch plates

    # dimension reference point is the center of the plate

    # returns a rectangular plate object

    # plate is aligned with brace member line

    def stitch_pl(mem, pnt1, width, length, thk, grade, color):

        ga = mem.LL_gage

        try:

            llv = mem.LLV

            if llv == "Outstanding":

                ga = mem.SL_gage

        except:

            pass

        if mem.angle_leg_up == 'Yes':

            ga *= -1

        Y_offset = mem.trans_to_local(mem.main_mtrl().pt1 - \

                                      mem.left_location).y - ga

        # rectangular plate begin

        rp1 = RectPlate()

        rp1.member = mem

        rp1.pt1 = pnt1 + mem.translate(-length/2, width/2 + Y_offset, 0.0)

        rp1.pt2 = rp1.pt1 + mem.translate(length, 0.0, 0.0)

        rp1.mtrl_usage = "Stitch Plate"

        rp1.grade = grade

        rp1.origin = "Center"

        rp1.width = width

        rp1.thick = thk

        rp1.work_pt_dist = length

        rp1.length = length

        rp1.mtrl_type = "Plate"

        rp1.finish = color

        rp1.ref_pt_offset = (rp1.length/2, -rp1.width/2, 0.000000)

        rp1.add()

        # rp1.rotate(rp1.member, rot_arg)

        # rectangular plate end

        return rp1

    #### plate add for welded stitches

    def welded_stitch_pl(mem, pnt1, width, length, thk, grade, color):

        # width is the projection of the stitch

        pl_width = width*2 + mem.depth

        try:

            llv = mem.LLV

            if llv == "Outstanding":

                pl_width = width*2 + mem.bf

        except:

            pass

        y_offset = mem.trans_to_local(mem.main_mtrl().pt1 - \

                                      mem.left_location).y + width

        if mem.angle_leg_up == 'Yes':

            y_offset += pl_width - width*2

        # rectangular plate begin

        rp1 = RectPlate()

        rp1.member = mem

        rp1.pt1 = pnt1 + mem.translate(-length/2, y_offset, 0.0)

        rp1.pt2 = rp1.pt1 + mem.translate(length, 0.0, 0.0)

        rp1.mtrl_usage = "Stitch Plate"

        rp1.grade = grade

        rp1.origin = "Center"

        rp1.width = pl_width

        rp1.thick = thk

        rp1.work_pt_dist = length

        rp1.length = length

        rp1.mtrl_type = "Plate"

        rp1.finish = color

        rp1.ref_pt_offset = (rp1.length/2, -y_offset, 0.000000)

        rp1.add()

        # rp1.rotate(rp1.member, rot_arg)

        # rectangular plate end

        return rp1

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

    # add hole to plate material

    def pl_holes(rl9, ht, bt, bs):

        # calculate hole location from dimensions of stitch plate

        # hole to placed in the middle of the plate

        # hole group add begin

        hole26 = Hole()

        hole26.mtrl = [rl9, ]

        hole26.pt1 = rl9.pt1 + rl9.translate(rl9.length/2, -rl9.width/2, 0.0)

        hole26.hole_type = ht

        hole26.face = "NS Face"

        hole26.valid_cnc = "Yes"

        hole26.x_ref_offset = 0.0

        hole26.y_ref_offset = 0.0

        hole26.group_rot = 0.0

        hole26.locate = "Center"

        hole26.columns = 1

        hole26.rows = 1

        hole26.bolt_type = bt

        hole26.bolt_dia = bs

        hole26.hole_dia = hole26.calc_hole_size()

        hole26.create()

        # hole group add end

        return hole26

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

    def pt(mem, spa1, spa2, spa3, j):

        dist1 = mem.left.setback + spa1 + spa2 + (spa3 * j)

        return mem.left_location + mem.translate(dist1, 0.0, 0.0)

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

    # 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:

        ClearSelection()

        # Select member

        # mem_list = mem_select("Select brace member", ['Vertical Brace', 'Horizontal Brc'], ['Angle', ], False, False)

        mem_list = memAreaSelect("Select brace members by area", ['Vertical Brace', 'Horizontal Brc'], ['Angle', ])

        # mem1 = mem_list[0]

       

        for mem in mem_list:

            # mem.highlight()

            matl_length = mem.left.location.dist(mem.right.location) - mem.left.setback - mem.right.setback

            matlList = list_mtrl(mem)

            # In SDS/2 version 7.110, thickness can be determined by calculating the distance between the member main materials

            # which can be compiled by checking attribute 'mem.mtrl_is_main'

            if len(matlList) > 2:       # there probably is a gusset plate

                for m in matlList:

                    if m.mtrl_type == 'Plate':

                        bltd_thk = m.thick

                        wldd_thk = m.thick

                        break

            elif len(matlList) == 2:    # there are probably just 2 angles

                wldd_thk = matlList[0].pt1.dist(matlList[1].pt1)

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

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

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

            dlg1 = Dialog("Add stitch plate(s) to a vertical brace")

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

           

            dlg1.line("Mark: %s - Material length: %s" % (mem.piecemark, dim_print(matl_length)))

            dlg1.line("Material found on brace:")

            for m in iter_mtrl(mem):

                dlg1.line("%s - %sx%s %s" % (m.piecemark, m.description, dim_print(m.length), m.mtrl_type))

               

            dlg1.tabset_begin()

            dlg1.tab("General Information")

            dlg1.group_title("General information")

            dlg1.menu("stitch_type", ("Welded", "Bolted"), stitch_type, "Stitch type                                       ")

            dlg1.entry("max_stitch_spacing", dim_print(max_stitch_spacing), "Maximum spacing of stitch plates                  ")

            dlg1.entry("min_no_stitch", min_no_stitch, "Enter minimum number of stitch plates")

            dlg1.menu("pl_color", finishList, pl_color, "Select material color" )

            dlg1.menu("steelgrade", gradeList, steelgrade, "Select plate material grade")

 

            dlg1.tab("Bolted stitch")

            dlg1.group_title("Dimensions")

            dlg1.entry("bltd_thk", dim_print(bltd_thk), "Stitch thickness")

            dlg1.entry("bltd_width", dim_print(bltd_width), "Stitch width")

            dlg1.entry("bltd_length", dim_print(bltd_length), "Stitch length")           

           

            dlg1.group_title("Stitch bolt information")

            dlg1.entry( "stitch_bolt_size", dim_print(stitch_bolt_size), "Bolt size")

            dlg1.menu( "stitch_hole_type", holetypeList, stitch_hole_type, "Hole type in shear tab")

            dlg1.menu( "stitch_bolt_type", bolttypeList, stitch_bolt_type, "Bolt type")

           

            dlg1.group_title("Determine distance between attachments")

            dlg1.entry("no_bolts", no_bolts, "Number of bolts in end connection @ 3 in c/c")

 

            dlg1.tab("Welded stitch")

            dlg1.group_title("Dimensions")

            dlg1.entry("wldd_thk", dim_print(wldd_thk), "Stitch thickness")

            dlg1.entry("wldd_width", dim_print(wldd_width), "Stitch projection")

            dlg1.entry("wldd_length", dim_print(wldd_length), "Stitch length")

           

            dlg1.group_title("Determine distance between attachments")

            dlg1.entry("weld_length", dim_print(weld_length), "Weld length or dist to inner attachment")

           

            try:

                dd1 = dlg1.done()

            except ResponseNotOK:

                break

            for key, value in dd1.items():

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

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

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

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

            if print_doc == "Yes":

                print __doc__

                break

           

            # Export defaults to disk if enabled

            if enable_default_import_export == "Enable":

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

 

            if stitch_type == "Bolted":           

                end_to_inner_attachment = ((no_bolts - 1) * bolt_spa) + Fabricator().edge_dist_vbrc

            else:

                end_to_inner_attachment = weld_length

               

            dist_between_attach = matl_length - (end_to_inner_attachment * 2)

            no_stitch = int(max((ceil(dist_between_attach / max_stitch_spacing) - 1), min_no_stitch))

            spacing_stitch = dist_between_attach / (no_stitch + 1)

            first_space = spacing_stitch

           

            ''' Code for setting even spacing for stitches between closest points of attachment

            if no_stitch > 1:

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

                ## DIALOG BOX 2 --------------------------------------------------------------------------#

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

                dlg2 = Dialog("Stitch spacing")

                dlg2.group_title("Mark: %s - Material length: %s" % (mem.piecemark, dim_print(matl_length)))

                dlg2.line("Number of stitches = " + str(no_stitch))

                dlg2.entry("spacing_stitch", dim_print(spacing_stitch), "Enter stitch spacing")

               

                try:

                    dd2 = dlg2.done()

                except ResponseNotOK:

                    break

                for key, value in dd2.items():

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

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

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

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

                if abs(spacing_stitch - first_space) < eps:

                    first_space = (dist_between_attach - spacing_stitch * (no_stitch - 1)) / 2.0

            '''

            pt_list = [pt(mem, end_to_inner_attachment, first_space, spacing_stitch, i) for i in range(no_stitch)]

 

            if stitch_type == "Bolted":           

                for pnt in pt_list:

                    rp11 = stitch_pl(mem, pnt, bltd_width, bltd_length, bltd_thk, steelgrade, pl_color)

                    hole11 = pl_holes(rp11, stitch_hole_type, stitch_bolt_type, stitch_bolt_size)

                    # match holes and add bolts

                    for mtrl in [m for m in iter_mtrl(mem) if m.description == mem.size]:        # 7.107

                    # for mtrl in [m for m in iter_mtrl(mem) if m.mtrl_is_main =='Yes']:             # 7.110

                        hole_match(mtrl, hole11)

                    # parametrically added bolts are bad in version 7.107

                    # bolt_match(rp11, list(iter_mtrl(mem)))

            else:

                for pnt in pt_list:

                    rp11 = welded_stitch_pl(mem, pnt, wldd_width, wldd_length, wldd_thk, steelgrade, pl_color)

                    # welding not supported at this time

                   

            # does not work:

            # mem.unhighlight()

            SelectionToggle(mem)

 

        if not yes_or_no("Add more stitch plates?"):

            break

       

## End run_script()

if __name__ == '__main__':

    try:

        run_script()

    finally:

        del run_script

        ClearSelection()