# coding: utf-8
#
# Copyright © 2020 MSC.Software Corporation
#  
# Permission to use Scripts
#  
# Permission is granted to MSC.Software customers with valid licenses of the MSC Apex™ software 
# to use script files posted on this page (collectively “Scripts”) solely for customers’ own authorized 
# internal use in conjunction with licensed use of the MSC Apex software.  
# No other use is permitted.  No license to MSC Apex or other software is granted under this Permission.
#  
# SCRIPTS ARE PROVIDED ON AN "AS-IS" BASIS, WITH NO WARRANTIES OF ANY KIND.  USE OF THE SCRIPTS IS AT CUSTOMER'S SOLE RISK.
#  
# IN NO EVENT SHALL MSC.SOFTWARE CORPORATION, ITS AFFILIATES, SUBSIDIARIES, SUPPLIERS, AGENTS, REPRESENTATIVES OR EMPLOYEES BE LIABLE FOR ANY 
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, TORT, 
# STRICT LIABILITY, OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION USE OF THE SCRIPTS, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
#  
# Customer shall indemnify, defend and hold MSC.Software Corporation, its affiliates, subsidiaries, suppliers, agents, 
# employees or representatives (collectively, “Indemnified Parties”) harmless from and against any third-party claims 
# brought against Indemnified Parties rising out of or in connection with Customer’s use of the Scripts.
#

# Author: Larry Pearce
# Revised by: Larry Pearce
# Revision History
# Date         Change                                 By
# 2020-10-13   Original code (1.0)                    Larry Pearce

import apex
import math


def calcDist(n1, n2):
    # Input:   variable        datatype         description
    #          n1              object
    #          n2              object
    # Output:  variable        datatype         description
    #          dist            real             distance
    #
    # Get the distance between 2 objects/locations/coordinates

    dx = n2.getX() - n1.getX()
    dy = n2.getY() - n1.getY()
    dz = n2.getZ() - n1.getZ()

    dist = dx*dx + dy*dy + dz*dz
    if dist > 0.0: dist = math.sqrt(dist)

    return dist


def connectorProps(stiff):
    # Input:   variable        datatype         description
    #          stiff           list of cbush stiffnesses
    # Output:  variable        datatype         description
    #          connProp        object           connector property
    #
    # Creates a CBUSH connector property

    connProp = apex.attribute.createConnectorProperties(
          stiffness               = 0.0,
          damping                 = 0.0,
          translationalStiffnessX = stiff[0],
          translationalStiffnessY = stiff[1],
          translationalStiffnessZ = stiff[2],
          rotationalStiffnessX    = stiff[3],
          rotationalStiffnessY    = stiff[4],
          rotationalStiffnessZ    = stiff[5],
          translationalDampingX   = 0.0,
          translationalDampingY   = 0.0,
          translationalDampingZ   = 0.0,
          rotationalDampingX      = 0.0,
          rotationalDampingY      = 0.0,
          rotationalDampingZ      = 0.0,
          diameter                = 0.0,
          linkMaterial            = None)

    return connProp


def updateCbushStiff(connProp, updateStiff, stiff):
    # THIS DID NOT WORK FOR ME
    if updateStiff[0]: connProp.update(translationalStiffnessX = stiff[0])
    if updateStiff[1]: connProp.update(translationalStiffnessY = stiff[1])
    if updateStiff[2]: connProp.update(translationalStiffnessZ = stiff[2])
    if updateStiff[3]: connProp.update(rotationalStiffnessX    = stiff[3])
    if updateStiff[4]: connProp.update(rotationalStiffnessY    = stiff[4])
    if updateStiff[5]: connProp.update(rotationalStiffnessZ    = stiff[4])


def calcBushingPropsQRG(dia, length, matl):
    # Input:   variable        datatype         description
    #          dia             real             fastener diameter
    #          length          real             fastener length
    #          matl            object           material
    # Output:  variable        datatype         description
    #          stiff           list of stiffnesses
    #
    # Calculates fastener stiffness per formulas from QRG for PFAST

    E  = matl.getElasticModulus()
    NU = matl.getPoissonRatio()
    G  = E/2.0/(1.0+NU)

    Area    = math.pi*dia**2/4.0
    Inertia = math.pi*dia**4/64.0
    J       = 2.0*Inertia

    shearArea = 0.75*Area

    stiff = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]

    if length > 0.0:
        stiff[0] = E*Area/length
        stiff[1] = G*shearArea/length
        stiff[2] = stiff[1]
        stiff[3] = G*J/length
        stiff[4] = E*Inertia/length + G*shearArea*length/3.0
        stiff[5] = stiff[4]

    return stiff


def main(dict={}):
    stiff       = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
    updateStiff = [False, False, False, False, False, False]
    myModel = apex.currentModel()

    stiffnessMethod = dict["stiffnessMethod"]
    if stiffnessMethod == "Direct Input":
        processUpdate = False
        for k in range(6):
            print(dict[str(k)+"_toggle"])
            if dict[str(k)+"_toggle"] == "True":
                try:
                    d = float(dict[str(k)+"_val"])
                except:
                    d = "Not a float"
                if d != "Not a float":
                    stiff[k]       = float(dict[str(k)+"_val"])
                    updateStiff[k] = True
                    processUpdate  = True
                else:
                    updateStiff[k] = False
            else:
                updateStiff[k] = False
            print("Stiffness "+str(k))
            print("  Update: "+str(updateStiff[k]))
            print("  Stiffness: "+str(stiff[k]))

        if not processUpdate:
            print("No stiffness values defined?")
            return
    if stiffnessMethod == "Nastran QRG":
        matlName    = dict["material"]
        dia         = float(dict["diameter"])
        fastenerMatl = None
        matls = apex.catalog.getMaterials([{"path":myModel.getName()+"/Materials"}])
        for matl in matls:
            if matl.getName() == matlName:
                fastenerMatl = matl
                break
        if fastenerMatl is None:
            print("Unknown material?")
            return
        if dia <= 0.0:
            print("Diameter <= 0.0!")
            return

    _selected = apex.selection.getCurrentSelection()

    print("Selected connectors: "+str(_selected.len()))

    if _selected.len() == 0:
        print("Processing Assemblies for connections ...")
        assys = myModel.getAssemblies()
        if assys.len() == 0:
            print("No Assemblies found!")
            return
        for assy in assys:
            conns = apex.attribute.getConnectors([{"path":assy.getPath()}])
            _selected.extend(conns)
        print("Assembly connectors: " + str(_selected.len()))
    if _selected.len() == 0:
        print("No connectors selected nor found in an Assembly!")
        return

    print("Processing " + str(_selected.len()) + " connectors")

    numConnectors = 0
    numNotCbush   = 0
    for conn in _selected:
        if conn.getConnectorType() != apex.attribute.ConnectorType.Bushing:
            numNotCbush += 1
            continue

        if stiffnessMethod == "Nastran QRG":
            c1 = conn.getEnd1InterfacePoint().getAssociatedEntity().asNode()
            c2 = conn.getEnd2InterfacePoint().getAssociatedEntity().asNode()
            length = calcDist(c1, c2)
            if length == 0.0:
                print("Unable to update connector via QRG method as connector length is ZERO!")
                continue
            stiff = calcBushingPropsQRG(dia, length, fastenerMatl)
        else:
            if not updateStiff[0]: stiff[0] = conn.getTranslationalStiffnessX()
            if not updateStiff[1]: stiff[1] = conn.getTranslationalStiffnessY()
            if not updateStiff[2]: stiff[2] = conn.getTranslationalStiffnessZ()
            if not updateStiff[3]: stiff[3] = conn.getRotationalStiffnessX()
            if not updateStiff[4]: stiff[4] = conn.getRotationalStiffnessY()
            if not updateStiff[5]: stiff[5] = conn.getRotationalStiffnessZ()

        connProps = connectorProps(stiff)

        conn.update(connectorProperties = connProps)

        numConnectors += 1

    print("CBUSH connectors updated: "+str(numConnectors))

    print(str(numNotCbush) + "of the selected connectors were not CBUSH connectors")



