##  kicker.py Version 1.00 (module macrolib.kicker)

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

##  All rights reserved.

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

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

'''

/// Functions:

///     kicker_pl(bm, p1, p2, clip, grade, width, thk, finish, rotpl, sl)

///         Returns a rectangular plate object

///         The thickness reference is 'Center'

///         Point p2 defines the plate length

///         'sl' is the beam slope.

///         'rotpl' is a tuple containing the material rotation arguments

///

///     gpl_hole (rect_pl, hl_ref_pt, hl_face, x_off, y_off, bd, hs, ht, \

///               bt, quadrant, no_x, no_y, spa_x, spa_y):

///         Returns a hole object.

///         "UL" (upper left) and "LL" (lower left) indicates the hole pattern

///         work point location with respect to the hole pattern.

///         hole26.locate expects the pattern location with respect to the WP -

///         hence "Below Right" and "Above Right".

///         positional arguments: material object, hole reference point,

///         hole face, 'x' offset, 'y' offset, bolt diameter, slot length,

///         hole type, bolt type, quadrant ('UL', 'LL', 'UR', 'LR')+

///         (relative position tuple), number of columns (mtrl 'x' direction),

///         number of rows (mtrl 'y' direction), column spacing, row spacing

///         relative position tuple:

///             ('Above Left', 'Above Center', 'Above Right', 'Center Left', \

///              'Center', 'Center Right', 'Below Left', 'Below Center', 'Below Right')

///         If 'ht'='Long Slot' and 'hs' is False or '0', slot length is calculated.

///

///     add_kicker_pl(pt_list, bm_list, dd)

///         Return a list of rectangular plate objects

///         point list (list of user selected points), bm_list (list of members),

///         dd (dialog box dictionary)

///

///     add_kicker(p1, p2, mtrl_size, grade, mk, orient, ld, rot)

///         Return a rolled shape material object ('Angle')

///         WP1, WP2, material size, material grade, piecemark or '', 'HZ.' or 'VT',

///         leg direction ('In', 'Out'), rotation

'''

 

from macrolib.ExceptWarn import formatExceptionInfo

from macrolib.bolt_match import bolt_match

from math import cos, floor, pi, tan, sin, atan

from macrolib.Weld import mtrl_weld

from macrolib.angle import rtod, dtor, planRotPts

 

from rect_plate import RectPlate

from hole_add import Hole

from bolt_add import Bolt

from point import Point

from member import Member

 

 

# Add a kicker gusset plate

# reference points are the end points of the plate

# returns a rectangular plate object

def kicker_pl(bm, p1, p2, clip, grade, width, thk, finish, rotpl, sl):

    rot_arg = (rotpl[0], rotpl[1], (rotpl[2] - sl))

    if clip == 0.0:

        oper = "None"

    else:

        oper = "Clip"

    # rectangular plate begin

    rp1 = RectPlate()

    rp1.member = bm

    rp1.pt1 = p1

    rp1.pt2 = p2

    rp1.grade = grade

    rp1.origin = "Center"

    rp1.top_oper_left = oper

    rp1.top_length_left = clip

    rp1.top_clip_left = clip  

    rp1.width = width

    rp1.thick = thk

    rp1.work_pt_dist = p1.dist(p2)

    rp1.length = p1.dist(p2)

    rp1.mtrl_type = "Plate"

    rp1.mtrl_usage = "Kicker GPL"

    rp1.finish = finish

    rp1.ref_pt_offset = (0.000000, 0.000000, 0.000000)

    rp1.add()

    rp1.rotate(rp1.member, rot_arg)

    # rectangular plate end

    return rp1

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

 

# Define function to add pin hole in kicker gusset plate

def gpl_hole (rect_pl, hl_ref_pt, hl_face, x_off, y_off, bd, hs, ht, bt, quadrant='Center', no_x=1, no_y=1, spa_x=3.0, spa_y=3.0):

    ## "UL" (upper left) and "LL" (lower left) indicates the hole pattern work point location with respect to the hole pattern

    ## hole26.locate expects the pattern location with respect to the WP - hence "Below Right" and "Above Right"

    if quadrant == "UL":

        hl_patt = "Below Right"

    elif quadrant == "LL":

        hl_patt = "Above Right"

    elif quadrant == "UR":

        hl_patt = "Below Left"

    elif quadrant == "LR":

        hl_patt = "Above Left"

    else:

        hl_patt = quadrant

        

    if ht == "Long Slot":

        if hs:

            str1 = "hs"

        else:       

            str1 = "hole26.calc_slot_length()"

    else:

        str1 = "hole26.calc_slot_length()"

    try:

        # hole group add begin

        hole26 = Hole()

        hole26.mtrl = [rect_pl, ]

        hole26.pt1 = hl_ref_pt

        hole26.hole_type = ht

        hole26.face = hl_face

        hole26.valid_cnc = "Yes"

        hole26.x_ref_offset = x_off

        hole26.y_ref_offset = y_off

        hole26.x_spa = spa_x

        hole26.y_spa = spa_y

        hole26.group_rot = 0.0

        hole26.locate = hl_patt

        hole26.columns = no_x

        hole26.rows = no_y

        hole26.bolt_type = bt

        hole26.bolt_dia = bd

        hole26.slot_rot = 0.0

        hole26.length = eval(str1)

        hole26.hole_dia = hole26.calc_hole_size()

        hole26.show_window = "Yes"

        hole26.create()

        # hole group add end

        return hole26

    except:

        return None

 

# Return a list of rectangular plate objects

def add_kicker_pl(pt_list, bm_list, dd):

    rpList = []

   

    # mem1 is the first element in bm_list

    mem1 = bm_list[0]

   

    # Update the local namespace

    for key, value in dd.items():

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

       

    # Determine 'y' and 'z' offsets for HSS and WF members

    # For HSS members, top/bottom edge of plate to align with edge of roll - calculated as twice the wall thickness

    if mem1.mtrl_type == "Tube":

        z_offset = mem1.short_depth / 2

        y_offset = mem1.tf*2.0

    else:

        z_offset = mem1.tw / 2.0

        y_offset = mem1.tf

       

    if norm_or_vert == "Vertical":

        sl = mem1.slope

    else:

        sl = 0.0

   

    # convert points in pt_list to member coordinates for mem1 and create pt_list_loc

    pt_list_loc = []

    for pt in pt_list:

        pt = mem1.trans_to_local(pt - mem1.left_location)

        pt_list_loc.append((pt.x, pt.y, pt.z))

       

    # real1 is the distance from the top of the beam to the top of gusset if top_or_bott == "Top"

    real1 = (y_offset / cos(dtor(sl))) + (gpl_thk / 2) * abs(tan(dtor(sl)))

   

    # wp_length is the distance from the top of gusset at top flange to bottom of gusset at bottom flange

    wp_length = mem1.depth / cos(dtor(sl)) - (2 * real1)

   

    # calculate WP adjustments required for plate rotation 'theta'

    z_adjust = (gpl_thk/2.0) * sin(dtor(theta))

    x_adjust = ((mem1.tw/2.0)*tan(dtor(theta))) + ((gpl_thk/2.0) * tan(dtor(theta)) * abs(sin(dtor(theta))))

   

    # begin beam loop

    for bm in bm_list:

        # convert pt_list_loc to global coordinates

        pt_list = [(bm.left_location + bm.translate(x + points_x_offset, y, z)) for x,y,z in pt_list_loc]

           

        # begin loop for selected/calculated points

        for pt in pt_list:

            dist_h = Point(bm.left_location.x, bm.left_location.y, 0.0).dist(Point(pt.x, pt.y, 0.0))

            ang_1 = bm.plan_rotation

            if (pt.x - bm.left_location.x) == 0.0:

                ang_2 = 90.0

            else:

                ang_2 = rtod(atan((pt.y - bm.left_location.y) / (pt.x - bm.left_location.x)))

               

            ang_net = ang_1 - ang_2

            dist_b = abs((dist_h * cos(dtor(ang_net))) / cos(dtor(bm.slope)))

            ptWP = bm.left_location + bm.translate(dist_b, 0.0, 0.0)

            ptWP_Top = ptWP + mem1.translate(real1 * -sin(dtor(sl)), -real1 * cos(dtor(sl)), 0.0)

            ptWP_Bott = ptWP + mem1.translate(-(wp_length + real1) * sin(dtor(sl)), -(wp_length + real1) * cos(dtor(sl)), 0.0)

           

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

                if top_or_bott == "Top" or top_or_bott == "T&B":

                    pt32 = ptWP_Top + bm.translate(x_adjust, 0.0, z_offset + abs(z_adjust))

                    pt33 = pt32 + bm.translate(gpl_length * sin(dtor(sl)), -gpl_length * cos(dtor(sl)), 0.0)

                    rot_pl = (0.0, 90.0 - theta, 0.0)

                    rp11 = kicker_pl(bm, pt32, pt33, gpl_clip, matlgrade, gpl_width, gpl_thk, matlcolor, rot_pl, sl)

                    rpList.append(rp11)

                   

                    if add_pin_hole == "Yes":

                        gpl_hole (rp11, pt32, "NS Face", x_ga, y_ga, bolt_size, long_slot_length, \

                                  hole_type, bolt_type, "UL", 1, 1, 3.0, 3.0)

                       

                    if add_gpl_weld == "Yes":

                        mtrl_weld([bm, ], [rp11, ], weld_size, gpl_weld_type)

   

                       

                if top_or_bott == "Bott" or top_or_bott == "T&B":

                    pt32 = ptWP_Bott + bm.translate(x_adjust, 0.0, z_offset + abs(z_adjust))

                    pt33 = pt32 + bm.translate(-gpl_length * sin(dtor(sl)), gpl_length * cos(dtor(sl)), 0.0)

                    rot_pl = (0.0, 90.0 + theta, 180.0)

                    rp11 = kicker_pl(bm, pt32, pt33, gpl_clip, matlgrade, gpl_width, gpl_thk, matlcolor, rot_pl, sl)

                    rpList.append(rp11)

                   

                    if add_pin_hole == "Yes":

                        gpl_hole (rp11, pt32, "NS Face", x_ga, y_ga, bolt_size, long_slot_length, \

                                  hole_type, bolt_type, "UL", 1, 1, 3.0, 3.0)

                    if add_gpl_weld == "Yes":

                        mtrl_weld([bm, ], [rp11, ], weld_size, gpl_weld_type)

                       

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

                if top_or_bott == "Top" or top_or_bott == "T&B":

                    pt32 = ptWP_Top + bm.translate(-x_adjust, 0.0, -z_offset - abs(z_adjust))

                    pt33 = pt32 + bm.translate(gpl_length * sin(dtor(sl)), -gpl_length * cos(dtor(sl)), 0.0)

                    rot_pl = (0.0, -90.0 - theta, 0.0)

                    rp12 = kicker_pl(bm, pt32, pt33, gpl_clip, matlgrade, gpl_width, gpl_thk, matlcolor, rot_pl, sl)

                    rpList.append(rp12)

                   

                    if add_pin_hole == "Yes":

                        gpl_hole (rp12, pt32, "NS Face", x_ga, y_ga, bolt_size, long_slot_length, \

                                  hole_type, bolt_type, "UL", 1, 1, 3.0, 3.0)

                    if add_gpl_weld == "Yes":

                        mtrl_weld([bm, ], [rp12, ], weld_size, gpl_weld_type)

                       

                if top_or_bott == "Bott" or top_or_bott == "T&B":

                    pt32 = ptWP_Bott + bm.translate(-x_adjust, 0.0, -z_offset - abs(z_adjust))

                    pt33 = pt32 + bm.translate(-gpl_length * sin(dtor(sl)), gpl_length * cos(dtor(sl)), 0.0)

                    rot_pl = (0.0, -90.0 + theta, 180.0)

                    rp12 = kicker_pl(bm, pt32, pt33, gpl_clip, matlgrade, gpl_width, gpl_thk, matlcolor, rot_pl, sl)

                    rpList.append(rp12)

                   

                    if add_pin_hole == "Yes":

                        gpl_hole (rp12, pt32, "NS Face", x_ga, y_ga, bolt_size, long_slot_length, \

                                  hole_type, bolt_type, "UL", 1, 1, 3.0, 3.0)

                    if add_gpl_weld == "Yes":

                        mtrl_weld([bm, ], [rp12, ], weld_size, gpl_weld_type)

    return rpList

 

# add a miscellaneous member, rolled 'Angle' material

# orient = "HZ." or "VT."

def add_kicker(p1, p2, mtrl_size, grade, mk, orient, ld, rot):

    # member begin

    memadd1 = Member('Misc Rolled Section')

    memadd1.left.location = p1

    memadd1.right.location = p2

    memadd1.section_size = mtrl_size

    memadd1.grade = grade

    memadd1.piecemark = mk

    memadd1.centered = "No"

    memadd1.llv = orient

    memadd1.toeio = ld

    memadd1.rolling_op = "None"

    memadd1.work_pt_dist = p1.dist(p2)

    memadd1.setback_left = 0

    memadd1.setback_right = 0

    memadd1.end_cut_left = "Standard Cut"

    memadd1.end_cut_right = "Standard Cut"

    memadd1.length = memadd1.work_pt_dist

    memadd1.mtrl_type = "Angle"

    memadd1.mtrl_usage = "KICKER"

    memadd1.finish = "Gray oxide"

    memadd1.ref_pt_offset = (0, 0, 0)

    memadd1.add()

    memadd1.rotate(rot)

    # member end

    return memadd1

# function to add holes to the embedded plate

 

## End of file