From c48a5060f49288e0b2e0e6dad8a5218efead6131 Mon Sep 17 00:00:00 2001 From: camilo carvajal Date: Sun, 11 May 2025 21:16:32 -0500 Subject: [PATCH] Several functions implemented , also order functions --- openstaad/command.py | 18 ++ openstaad/geometry.py | 124 +++++++++---- openstaad/load.py | 148 ++++++++++++++-- openstaad/output.py | 38 +++- openstaad/properties.py | 377 +++++++++++++++++++++------------------- openstaad/root.py | 31 ++-- openstaad/support.py | 37 +++- openstaad/tools.py | 3 +- openstaad/view.py | 150 ++++++++++++---- 9 files changed, 638 insertions(+), 288 deletions(-) diff --git a/openstaad/command.py b/openstaad/command.py index 653a5ab..d2a883b 100644 --- a/openstaad/command.py +++ b/openstaad/command.py @@ -9,6 +9,7 @@ def __init__(self): self._functions= [ 'PerformAnalysis', + 'CreateSteelDesignCommand' ] for function_name in self._functions: @@ -25,3 +26,20 @@ def PerformAnalysis(self,print_option:int): --> 0 - No Print """ self._command.PerformAnalysis(print_option) + + def CreateSteelDesignCommand(self,design_code:int, command_no:int,int_values:list[int],float_values:float,string_values:str,member_list:list[int]): + + def make_safe_array_long(array): + size = len(array) + return automation._midlSAFEARRAY(ctypes.c_long).create(array) + + safe_list_members = make_safe_array_long(member_list) + member_list = make_variant_vt_ref(safe_list_members, automation.VT_ARRAY | automation.VT_I4) + + safe_list_int = make_safe_array_long(int_values) + int_values = make_variant_vt_ref(safe_list_int, automation.VT_ARRAY | automation.VT_I4) + + self._command.CreateSteelDesignCommand(design_code,command_no,int_values,float_values,string_values,member_list) + + + diff --git a/openstaad/geometry.py b/openstaad/geometry.py index 7331689..446607c 100644 --- a/openstaad/geometry.py +++ b/openstaad/geometry.py @@ -11,43 +11,54 @@ def __init__(self): self._geometry = self._staad.Geometry self._functions= [ + "AddBeam", + "AddNode", + "ClearMemberSelection", + "CreatePhysicalMember", + "DeletePhysicalMember", + "DoTranslationalRepeat", + "GetAnalyticalMemberCountForPhysicalMember", + "GetAnalyticalMembersForPhysicalMember", + "GetBeamLength", + "GetBeamList", + "GetBeamsConnectedAtNode", + "GetGroupCount", + "GetGroupEntities", + "GetGroupEntityCount", + "GetGroupNames", + "GetIntersectBeamsCount", + "GetLastBeamNo", "GetLastNodeNo", + "GetLastPhysicalMemberNo", + "GetMemberCount", + "GetMemberIncidence", "GetNodeCoordinates", "GetNodeCount", "GetNodeDistance", "GetNodeIncidence", "GetNodeList", "GetNodeNumber", + "GetNoOfBeamsConnectedAtNode", + "GetNoOfSelectedBeams", "GetNoOfSelectedNodes", + "GetNoOfSelectedPhysicalMembers", + "GetPMemberCount", + "GetPhysicalMemberCount", + "GetPhysicalMemberList", + "GetPhysicalMemberUniqueID", + "GetSelectedBeams", "GetSelectedNodes", - 'GetBeamLength', - 'GetBeamList', - 'GetMemberCount', - 'GetLastBeamNo', - 'GetMemberIncidence', - 'GetNoOfSelectedBeams', - 'GetSelectedBeams', - 'GetNoOfBeamsConnectedAtNode', - 'GetBeamsConnectedAtNode', - 'GetGroupEntities', - 'GetGroupEntityCount', - 'ClearMemberSelection', - 'SelectMultipleBeams', - 'GetGroupCount', - 'GetGroupNames', - 'CreatePhysicalMember', - 'AddNode', - 'AddBeam', - 'DoTranslationalRepeat', - 'GetIntersectBeamsCount', - 'IntersectBeams' + "GetSelectedPhysicalMembers", + "IntersectBeams", + "SelectMultipleBeams", + "SelectMultiplePhysicalMembers", + "SelectPhysicalMember", + "SetPhysicalMemberUniqueID" ] for function_name in self._functions: self._geometry._FlagAsMethod(function_name) - ## NODE FUNCTIONS - def GetLastNodeNo(self): return self._geometry.GetLastNodeNo() @@ -119,8 +130,6 @@ def GetSelectedNodes(self): self._geometry.GetSelectedNodes(lista) return (lista[0]) - - ## BEAM FUNCTIONS def GetBeamLength(self,beam): length = round(self._geometry.GetBeamLength(beam)*1000)/1000 @@ -181,8 +190,6 @@ def GetBeamsConnectedAtNode(self,node): return list[0] - ## GROUP FUNCTIONS - def GetGroupEntityCount(self,group_name): return self._geometry.GetGroupEntityCount(group_name) @@ -230,16 +237,20 @@ def CreatePhysicalMember(self,member_list:list): lista_variant = make_variant_vt_ref(safe_list, automation.VT_ARRAY | automation.VT_I4) retval=self._geometry.CreatePhysicalMember(num,lista_variant,None) - - def AddNode(self,x:float=0.0,y:float=0.0,z:float=0.0): retval=self._geometry.AddNode(x,y,z) return retval - + def AddBeam(self,node_A,node_B): retval=self._geometry.AddBeam(node_A,node_B) return retval + + def DeletePhysicalMember(self,p_member:int): + self._geometry.DeletePhysicalMember(p_member) + def GetAnalyticalMemberCountForPhysicalMember(self,p_member:int): + return self._geometry.GetAnalyticalMemberCountForPhysicalMember(p_member) + def make_safe_array_long(data): if not isinstance(data, list): raise TypeError("Data must be a list of integers") @@ -257,7 +268,7 @@ def make_variant_vt_ref(safe_array, vt_type): variant.vt = vt_type variant._.parray = safe_array return variant - + def DoTranslationalRepeat(self, varLinkBays: bool, varOpenBase: bool, varAxisDir: int, varSpacingArray: list[float], varNobays: int, varRenumberBay: bool, varRenumberArray: list, varGeometryOnly: bool): try: @@ -274,7 +285,7 @@ def make_safe_array_double(array): except Exception as e: print(f"An error occurred in DoTranslationalRepeat: {e}") raise - + def IntersectBeams(self, Method: int, BeamNosArray: list[int], dTolerance: float, NewBeamNosArray: int): # Conversión de dTolerance @@ -298,7 +309,7 @@ def make_safe_array_long(array): # Llamada a la función interna retval = self._geometry.IntersectBeams(Method, BeamNosArray, dTolerance, NewBeamNosArray) return retval - + def GetIntersectBeamsCount(self, BeamNosArray: list[int], dTolerance: float): safe_n1 = make_safe_array_double(1) dTolerance = make_variant_vt_ref(safe_n1, automation.VT_R8) @@ -312,8 +323,51 @@ def make_safe_array_long(array): n_beams = self._geometry.GetIntersectBeamsCount(BeamNosArray, dTolerance) return n_beams - - + #Not Working yet + def GetAnalyticalMembersForPhysicalMember(self, p_member: int): + + no_am = self._geometry.GetAnalyticalMemberCountForPhysicalMember(p_member) + + if no_am == 0: + return [] + + safe_list = automation._midlSAFEARRAY(ctypes.c_int).create([0] * no_am) + + var_p_member = automation.VARIANT(p_member) + var_no_am = automation.VARIANT(no_am) + var_member_list = automation.VARIANT() + var_member_list._.c_void_p = ctypes.addressof(safe_list) + var_member_list.vt = automation.VT_ARRAY | automation.VT_I4 | automation.VT_BYREF + + self._geometry.GetAnalyticalMembersForPhysicalMember( + var_p_member, var_no_am, var_member_list + ) + + return list(safe_list) + + def GetLastPhysicalMemberNo(self): + return self._geometry.GetLastPhysicalMemberNo() + def GetNoOfSelectedPhysicalMembers(self): + return self._geometry.GetNoOfSelectedPhysicalMembers() + def GetPhysicalMemberCount(self): + return self._geometry.GetPhysicalMemberCount() + + def GetPhysicalMemberList(self): + no_p_members=self._geometry.GetPhysicalMemberCount() + + safe_list = make_safe_array_long(no_p_members) + lista = make_variant_vt_ref(safe_list, automation.VT_ARRAY | automation.VT_I4) + + self._geometry.GetPhysicalMemberList(lista) + + return (lista[0]) + + def GetPhysicalMemberUniqueID(self,p_member): + return self._geometry.GetPhysicalMemberUniqueID(p_member) + + def GetPMemberCount(self): + return self._geometry.GetPMemberCount() + \ No newline at end of file diff --git a/openstaad/load.py b/openstaad/load.py index 97ee8da..8bc0945 100644 --- a/openstaad/load.py +++ b/openstaad/load.py @@ -8,20 +8,29 @@ def __init__(self): self._load = self._staad.Load self._functions= [ - 'GetLoadCaseTitle', - 'AddMemberConcForce', - 'SetLoadActive', - 'CreateNewPrimaryLoad' + "AddMemberConcForce", + "AddResponseSpectrumLoadEx", + "AddSelfWeightInXYZ", + "AddWindDefinition", + "ClearPrimaryLoadCase", + "CreateNewPrimaryLoad", + "CreateNewReferenceLoad", + "DeleteDirectAnalysisDefinition", + "DeleteDirectAnalysisDefinitionParameter", + "DeleteWindDefinition", + "GetLoadCaseTitle", + "GetReferenceLoadCaseCount", + "SetLoadActive", + "SetReferenceLoadActive" ] for function_name in self._functions: self._load._FlagAsMethod(function_name) - def GetLoadCaseTitle(self,lc): - return self._load.GetLoadCaseTitle(lc) - def AddMemberConcForce(self,varBeamNo:list[int],varDirection:int,varForce:float,varD1:float,varD2:float): - + """ + Adds CONCENTRATED FORCE to beam(s). + """ def make_safe_array_long(array): size = len(array) return automation._midlSAFEARRAY(ctypes.c_long).create(array) @@ -29,10 +38,125 @@ def make_safe_array_long(array): safe_list = make_safe_array_long(varBeamNo) varBeamNo = make_variant_vt_ref(safe_list, automation.VT_ARRAY | automation.VT_I4) - self._load.AddMemberConcForce(varBeamNo,varDirection,varForce,varD1,varD2) + return self._load.AddMemberConcForce(varBeamNo,varDirection,varForce,varD1,varD2) + + def AddResponseSpectrumLoadEx(self, code_number:int, modal_combination:int, set_names_1:list, set_values_1:list, spectrum_data_pairs:list[tuple],set_names_2:list=None, set_values_2:list=None): + """Adds Response Spectrum load item to the currently active load case. + + Parameters + [in] code_number Response Spectrum Loading Code. Refer to the following table for the integers corresponding to different codes. + [in] modal_combination Modal combination rule. (SRSS = 0, ABS = 1, CQC = 2, ASCE = 3, TEN = 4, CSM = 5, GRP = 6) + [in] Set1Names VARIANT BSTR array containing parameter key words. Refer to the Techincal Reference sections as indicated below. + [in] Set1Vals Parameters values corresponding to the keywords supplied in varSet1Names array. + [in] Set2Names Optional VARIANT BSTR array containing parameter key words for the spectrum generation data command. NULL can be used if not neeed. + [in] Set2Vals Parameters values corresponding to the keywords supplied in varSet2Names array. NULL can be used if not needed. + [in] DataPairs VARIANT double array containing pairs of time period and accleration data. NULL can used if not needed. Inputs (varSet2Names, varSet2Vals) and (varDataPairs) are mutually exclusive, i.e. if one is specified, other should not specified. + """ + def make_safe_array_string1(values): + return automation._midlSAFEARRAY(automation.BSTR).create(values) + + def make_safe_array_double1(values): + return automation._midlSAFEARRAY(ctypes.c_double).create(values) - def SetLoadActive(self,varLoadNo:int): - self._load.SetLoadActive(varLoadNo) + array_names_1 = make_safe_array_string1(set_names_1) + array_values_1 = make_safe_array_double1(set_values_1) + + if spectrum_data_pairs is not None: + flat_spectrum = [val for pair in spectrum_data_pairs for val in pair] + arr_spectrum = make_safe_array_double1(flat_spectrum) + var_spectrum = make_variant_vt_ref(arr_spectrum, automation.VT_ARRAY | automation.VT_R8) + else: + var_spectrum = None + + var_set2_names = None + var_set2_vals = None + var_set1_names = make_variant_vt_ref(array_names_1, automation.VT_ARRAY | automation.VT_BSTR) + var_set1_vals = make_variant_vt_ref(array_values_1, automation.VT_ARRAY | automation.VT_R8) + + return self._load.AddResponseSpectrumLoadEx(code_number,modal_combination,var_set1_names,var_set1_vals,var_set2_names,var_set2_vals,var_spectrum) + + def AddSelfWeightInXYZ(self, load_direction: int, load_factor: float): + """ + Adds a self weight to the active load case. + """ + v_direction = automation.VARIANT() + v_direction.value = load_direction + + v_factor = automation.VARIANT() + v_factor.value = float(load_factor) + + return self._load.AddSelfWeightInXYZ(v_direction, v_factor) + + def AddWindDefinition(self,type_No:int,type_name:str): + """ + Adds a Wind Definition named type_name" with number ID type_No. + """ + return self._load.AddWindDefinition(type_No,type_name) + + def ClearPrimaryLoadCase(self,load_case:int,is_reference_lc:bool=False): + """ + Clears the load items in a specified Primary Load cases or Reference Load cases. + """ + return self._load.ClearPrimaryLoadCase(load_case,is_reference_lc) + def CreateNewPrimaryLoad(self,LoadTitle:str="LOAD CASE X"): - self._load.CreateNewPrimaryLoad(LoadTitle) \ No newline at end of file + """ + Creates new PRIMARY load case. + """ + return self._load.CreateNewPrimaryLoad(LoadTitle) + + def CreateNewReferenceLoad(self,load_No:int,loadcase_title:str,load_type:int): + """ + Creates a new Reference Load Definition and set as active. + """ + return self._load.CreateNewReferenceLoad(load_No,loadcase_title,load_type) + + def DeleteDirectAnalysisDefinition(self): + """ + Deletes whole Direct Analysis Definition. + """ + return self._load.DeleteDirectAnalysisDefinition() + + def DeleteDirectAnalysisDefinitionParameter(self,parameter_type:int=0): + """ + Deletes respective parameters from Direct Analysis Definition based on the Parameter Type passed as argument (FLEX/AXIAL). + Flex --- 0 + Axial --- 2 + """ + return self._load.DeleteDirectAnalysisDefinitionParameter(parameter_type) + + def DeleteWindDefinition(self,type_No:int=0): + """ + Deletes Wind definition. All definitions will be deleted if this input is set as 0. + """ + return self._load.DeleteWindDefinition(type_No) + + def GetLoadCaseTitle(self,lc:int=0): + """ + Returns title of the specified load case as a text string. Input 0 to retrieve title of current active load case or reference load case. + """ + return self._load.GetLoadCaseTitle(lc) + + def GetReferenceLoadCaseCount(self): + """ + Returns the number of reference load case defined in Reference Load Definitions. + """ + return self._load.GetReferenceLoadCaseCount() + + def SetLoadActive(self,load_case:int): + """ + Makes the specified load number active, in order to add or remove load item(s). + """ + return self._load.SetLoadActive(load_case) + + def SetReferenceLoadActive(self,load_case:int): + """ + Identify a Load Case in Load Case Details to add, count and get reference load item(s). + """ + return self._load.SetReferenceLoadActive(load_case) + + + + + diff --git a/openstaad/output.py b/openstaad/output.py index b00ae7d..25aa489 100644 --- a/openstaad/output.py +++ b/openstaad/output.py @@ -9,15 +9,18 @@ def __init__(self): self._functions= [ 'GetMemberEndForces', + 'GetModalMassParticipationFactors', + 'GetModeFrequency', 'GetSupportReactions' ] for function_name in self._functions: self._output._FlagAsMethod(function_name) - ## PROPERTIES FUNCTIONS - def GetMemberEndForces(self,beam, start = True, lc :int= 1,local: int = 0): + """ + Get the end forces (FX, FY, FZ, MX, MY, MZ) at a specified end of a member for a given load case. + """ safe_n1 = make_safe_array_double(6) x = make_variant_vt_ref(safe_n1, automation.VT_ARRAY | automation.VT_R8) @@ -30,11 +33,38 @@ def GetMemberEndForces(self,beam, start = True, lc :int= 1,local: int = 0): return x.value[0] - def GetSupportReactions(self, node,lc :int= 1): + def GetModalMassParticipationFactors(self, var_mode: int): + """ + Get the modal mass participation factors in X, Y and Z directions for a given mode. + """ + patX = ctypes.c_double() + patY = ctypes.c_double() + patZ = ctypes.c_double() + + retval = self._output.GetModalMassParticipationFactors(var_mode, ctypes.byref(patX), ctypes.byref(patY), ctypes.byref(patZ)) + + return (round(patX.value,5), round(patY.value,5), round(patZ.value,5)) + + def GetModeFrequency(self, var_mode:int): + """ + Get the natural frequency (Hz) for a given mode. + """ + frequency = ctypes.c_double() + retval = self._output.GetModeFrequency(var_mode, ctypes.byref(frequency)) + + return (round(frequency.value,3)) + + def GetSupportReactions(self, node: int,lc :int= 1): + """ + Get the support reactions (FX, FY, FZ, MX, MY, MZ) at a specified node for a given load case. + """ safe_n1 = make_safe_array_double(6) x = make_variant_vt_ref(safe_n1, automation.VT_ARRAY | automation.VT_R8) retval = self._output.GetSupportReactions(node,lc,x) - return x.value[0] \ No newline at end of file + return x.value[0] + + + \ No newline at end of file diff --git a/openstaad/properties.py b/openstaad/properties.py index 5953e55..65331d2 100644 --- a/openstaad/properties.py +++ b/openstaad/properties.py @@ -8,174 +8,73 @@ def __init__(self): self._property = self._staad.Property self._functions= [ - 'GetBeamSectionName', - 'GetBeamSectionPropertyRefNo', - 'GetSectionPropertyValues', - 'GetAlphaAngleForSection', - 'GetMemberReleaseSpecEx', - 'GetMemberSpecCode', - 'CreateBeamPropertyFromTable', - 'CreateMemberReleaseSpec', - 'AssignMemberSpecToBeam', - 'AssignBeamProperty', - 'AssignMaterialToMember' + "AssignBeamProperty", + "AssignMaterialToMember", + "AssignMemberSpecToBeam", + "CreateBeamPropertyFromTable", + "CreateMemberReleaseSpec", + "GetAlphaAngleForSection", + "GetBeamSectionName", + "GetBeamSectionPropertyRefNo", + "GetMemberReleaseSpecEx", + "GetMemberSpecCode", + "GetSectionPropertyValues" ] for function_name in self._functions: self._property._FlagAsMethod(function_name) - ## PROPERTIES FUNCTIONS - - def GetBeamSectionName(self,beam): - return self._property.GetBeamSectionName(beam) - - def GetBeamSectionPropertyRefNo(self,beam): - return self._property.GetBeamSectionPropertyRefNo(beam) - - - def GetSectionPropertyValues(self,ref_no): - """ [out] varfWidth Width of the section (WID). - [out] varfDepth Depth of the section (DEP). - [out] varfAx Cross section area (Ax). - [out] varfAy Shear area in local y-axis. If zero, shear deformation is ignored in the analysis (Ay). - [out] varfAz Shear area in local z-axis. If zero, shear deformation is ignored in the analysis (Az). - [out] varfIx Moment of inertia about local z-axis (Ix). - [out] varfIy Moment of inertia about local y-axis (Iy). - [out] varfIz Torsional constant (Iz). - [out] varfTf Thickness of top flange (Tf). - [out] varfTw Thickness of web (Tw). + def AssignBeamProperty(self, beams_list: list[int], propertyNo: int): """ + Assign beam property. + """ + def make_safe_array_long(array): + size = len(array) + return automation._midlSAFEARRAY(ctypes.c_long).create(array) - safe_n1 = make_safe_array_double(1) - n1 = make_variant_vt_ref(safe_n1, automation.VT_R8) - - safe_n2 = make_safe_array_double(1) - n2 = make_variant_vt_ref(safe_n2, automation.VT_R8) - - safe_n3 = make_safe_array_double(1) - n3 = make_variant_vt_ref(safe_n3, automation.VT_R8) - - safe_n4 = make_safe_array_double(1) - n4 = make_variant_vt_ref(safe_n4, automation.VT_R8) - - safe_n5 = make_safe_array_double(1) - n5 = make_variant_vt_ref(safe_n5, automation.VT_R8) - - safe_n6 = make_safe_array_double(1) - n6 = make_variant_vt_ref(safe_n6, automation.VT_R8) - - safe_n7 = make_safe_array_double(1) - n7 = make_variant_vt_ref(safe_n7, automation.VT_R8) - - safe_n8 = make_safe_array_double(1) - n8 = make_variant_vt_ref(safe_n8, automation.VT_R8) - - safe_n9 = make_safe_array_double(1) - n9 = make_variant_vt_ref(safe_n9, automation.VT_R8) + safe_list = make_safe_array_long(beams_list) + beams_list = make_variant_vt_ref(safe_list, automation.VT_ARRAY | automation.VT_I4) - safe_n10 = make_safe_array_double(1) - n10 = make_variant_vt_ref(safe_n10, automation.VT_R8) + retval= self._property.AssignBeamProperty(beams_list, propertyNo) - - - ret_val = self._property.GetSectionPropertyValues(ref_no,n1,n2,n3,n4,n5,n6,n7,n8,n9,n10) - - a1 = round(n1.value[0]*1000)/1000 - a2 = round(n2.value[0]*1000)/1000 - a3 = round(n3.value[0]*1000000)/1000000 - a4 = round(n4.value[0]*1000000)/1000000 - a5 = round(n5.value[0]*1000000)/1000000 - a6 = round(n6.value[0]*1000000)/1000000 - a7 = round(n7.value[0]*1000)/1000 - a8 = round(n8.value[0]*1000)/1000 - a9 = round(n9.value[0]*1000)/1000 - a10 = round(n10.value[0]*1000)/1000 - - return {'Is_Ref':ret_val, - 'WID': a1, - 'DEP': a2, - 'Ax': a3, - 'Ay': a4, - 'Az': a5, - 'Ix': a6, - 'Iy': a7, - 'Iz': a8, - 'Tf': a9, - 'Tw': a10 - } + return retval - ## SPECIFICATIONS - - def GetAlphaAngleForSection(self,ref_no): + def AssignMaterialToMember(self, material_name: str, beamNo: list[int]): """ - Returns the alpha angle of the section in radian. - Gets the angle between the principal axis and geometric axis of the section - - Parameters: - [in] nPropNo The specified property ID. - [out] dAlpha alpha angle returned (in Radian). + Assign material to member. """ - safe_n1 = make_safe_array_double(0) - n1 = make_variant_vt_ref(safe_n1, automation.VT_R8) - - self._property.GetAlphaAngleForSection(ref_no,n1) - - return n1.value[0] - - ## SPECIFICATIONS - - def GetMemberReleaseSpecEx(self,beam, star = True): - ## solo funcionan ben el n1 que es el de los releses FX, FY, FZ, MX, MY, MZ - if star: - end = 0 - else: - end = 1 - - safe_n1 = make_safe_array_long(6) - n1 = make_variant_vt_ref(safe_n1, automation.VT_ARRAY | automation.VT_I4) - - safe_n2 = make_safe_array_long(6) - n2 = make_variant_vt_ref(safe_n2, automation.VT_ARRAY | automation.VT_I4) - - safe_n3 = make_safe_array_long(6) - n3 = make_variant_vt_ref(safe_n3, automation.VT_ARRAY | automation.VT_I4) - - safe_n4 = make_safe_array_long(6) - n4 = make_variant_vt_ref(safe_n4, automation.VT_ARRAY | automation.VT_I4) + def make_safe_array_long(array): + size = len(array) + return automation._midlSAFEARRAY(ctypes.c_long).create(array) + + safe_list = make_safe_array_long(beamNo) + beamNo = make_variant_vt_ref(safe_list, automation.VT_ARRAY | automation.VT_I4) - retval = self._property.GetMemberReleaseSpecEx(beam,end,n1,n2,n3,n4) + retval= self._property.AssignMaterialToMember(material_name, beamNo) - return n1.value[0] + return retval - def isrelease(self, memb): - rel_i = self.GetMemberReleaseSpecEx(memb, star=True) - rel_j = self.GetMemberReleaseSpecEx(memb,star=False) - - if rel_i == (0,0,0,0,0,0) and rel_j == (0,0,0,0,0,0): - return False - else: - return True - - def GetMemberSpecCode(self, memb): + def AssignMemberSpecToBeam(self, Beams: list[int], specNo: int): """ - Warning('GetMemberSpecCode output could be wrong') - 0-> Truss Member - 1-> Tension-only Member - 2-> Compression-only Member - 3-> Cable-only Member - 4-> Joist Member - -1-> Other + Assign specifications to beam(s). """ - make_safe_array_int = make_safe_array_long(1) - spe = make_variant_vt_ref(make_safe_array_int, automation.VT_ARRAY | automation.VT_I4) - # print(Warning('GetMemberSpecCode output could be wrong')) - return int(self._property.GetMemberSpecCode(memb,spe)) - + def make_safe_array_long(array): + size = len(array) + return automation._midlSAFEARRAY(ctypes.c_long).create(array) + + # Crear SAFEARRAY para 'release' + safe_list_release = make_safe_array_long(Beams) + Beams = make_variant_vt_ref(safe_list_release, automation.VT_ARRAY | automation.VT_I4) + retval= self._property.AssignMemberSpecToBeam(Beams, specNo) + return retval + def CreateBeamPropertyFromTable(self,Country_code:int,profile_name:str,type_spec:int=0,spec_1:float=0.0,spec_2:float=0.0): """ + Creates beam property from table. + COUNTRY CODE 1-> American 2-> Australian @@ -209,9 +108,11 @@ def CreateBeamPropertyFromTable(self,Country_code:int,profile_name:str,type_spec 30-> Australian cold formed """ propertyNo = self._property.CreateBeamPropertyFromTable(Country_code,profile_name,type_spec,spec_1,spec_2) - + def CreateMemberReleaseSpec(self, location: int, release: list[int], spring_const: list[float]): """ + Creates MEMBER RELEASE specification. + LOCATION 0 -> Start 1 -> End @@ -229,55 +130,175 @@ def make_safe_array_double(array): size = len(array) return automation._midlSAFEARRAY(ctypes.c_double).create(array) - # Crear SAFEARRAY para 'release' safe_list_release = make_safe_array_long(release) release_variant = make_variant_vt_ref(safe_list_release, automation.VT_ARRAY | automation.VT_I4) - # Crear SAFEARRAY para 'spring_const' safe_list_spring_const = make_safe_array_double(spring_const) spring_const_variant = make_variant_vt_ref(safe_list_spring_const, automation.VT_ARRAY | automation.VT_R8) - # Llamar a la función con los parámetros correctos retval = self._property.CreateMemberReleaseSpec(location, release_variant, spring_const_variant) return retval + + def GetAlphaAngleForSection(self,ref_no:int): + """ + Returns the alpha angle of the section in radian. + Gets the angle between the principal axis and geometric axis of the section - def AssignMemberSpecToBeam(self, Beams: list[int], specNo: int): - def make_safe_array_long(array): - size = len(array) - return automation._midlSAFEARRAY(ctypes.c_long).create(array) + Parameters: + [in] ref_no The specified reference property ID. + [out] dAlpha alpha angle returned (in Radian). + """ + + angle = ctypes.c_double() - # Crear SAFEARRAY para 'release' - safe_list_release = make_safe_array_long(Beams) - Beams = make_variant_vt_ref(safe_list_release, automation.VT_ARRAY | automation.VT_I4) + result = self._property.GetAlphaAngleForSection(ref_no, ctypes.byref(angle)) + + # Extraer el valor del parámetro de salida + angle_value = angle.value + + return angle_value + + def GetBeamSectionName(self,beam:int): + """ + Gets the section name of a given beam. + """ + return self._property.GetBeamSectionName(beam) - retval= self._property.AssignMemberSpecToBeam(Beams, specNo) + def GetBeamSectionPropertyRefNo(self,beam:int): + """ + Gets the section property reference number for a given beam. + """ + return self._property.GetBeamSectionPropertyRefNo(beam) - return retval + def GetMemberReleaseSpecEx(self,beam:int, start = True): + """ + Gets the member release specifications (FX, FY, FZ, MX, MY, MZ) for a given beam at a specified end. + """ + if start: + end = 0 + else: + end = 1 + + safe_n1 = make_safe_array_long(6) + n1 = make_variant_vt_ref(safe_n1, automation.VT_ARRAY | automation.VT_I4) + + safe_n2 = make_safe_array_long(6) + n2 = make_variant_vt_ref(safe_n2, automation.VT_ARRAY | automation.VT_I4) + + safe_n3 = make_safe_array_long(6) + n3 = make_variant_vt_ref(safe_n3, automation.VT_ARRAY | automation.VT_I4) + + safe_n4 = make_safe_array_long(6) + n4 = make_variant_vt_ref(safe_n4, automation.VT_ARRAY | automation.VT_I4) + + retval = self._property.GetMemberReleaseSpecEx(beam,end,n1,n2,n3,n4) + + return n1.value[0] - def AssignBeamProperty(self, beams_list: list[int], propertyNo: int): + def GetMemberSpecCode(self, memb:int): + """ + Obtain the code specification of member. - def make_safe_array_long(array): - size = len(array) - return automation._midlSAFEARRAY(ctypes.c_long).create(array) + Returns: + int: Specification Code + 0 -> Truss Member + 1 -> Tension-only Member + 2 -> Compression-only Member + 3 -> Cable-only Member + 4 -> Joist Member + -1 -> Other + """ - # Crear SAFEARRAY para 'beamNo' - safe_list = make_safe_array_long(beams_list) - beams_list = make_variant_vt_ref(safe_list, automation.VT_ARRAY | automation.VT_I4) + specCode = ctypes.c_long() + + result = self._property.GetMemberSpecCode(memb, ctypes.byref(specCode)) + + spec_value = specCode.value + + return spec_value + + def GetSectionPropertyValues(self,ref_no:int): + """ + Gets various geometric property values for a section given its reference number. The descriptions of the returned dictionary keys are based on the function's docstring. + Return: + [out] varfWidth Width of the section (WID). + [out] varfDepth Depth of the section (DEP). + [out] varfAx Cross section area (Ax). + [out] varfAy Shear area in local y-axis. If zero, shear deformation is ignored in the analysis (Ay). + [out] varfAz Shear area in local z-axis. If zero, shear deformation is ignored in the analysis (Az). + [out] varfIx Moment of inertia about local z-axis (Ix). + [out] varfIy Moment of inertia about local y-axis (Iy). + [out] varfIz Torsional constant (Iz). + [out] varfTf Thickness of top flange (Tf). + [out] varfTw Thickness of web (Tw). + """ - retval= self._property.AssignBeamProperty(beams_list, propertyNo) + safe_n1 = make_safe_array_double(1) + n1 = make_variant_vt_ref(safe_n1, automation.VT_R8) - return retval - - def AssignMaterialToMember(self, material_name: str, beamNo: list[int]): + safe_n2 = make_safe_array_double(1) + n2 = make_variant_vt_ref(safe_n2, automation.VT_R8) + + safe_n3 = make_safe_array_double(1) + n3 = make_variant_vt_ref(safe_n3, automation.VT_R8) + + safe_n4 = make_safe_array_double(1) + n4 = make_variant_vt_ref(safe_n4, automation.VT_R8) + + safe_n5 = make_safe_array_double(1) + n5 = make_variant_vt_ref(safe_n5, automation.VT_R8) + + safe_n6 = make_safe_array_double(1) + n6 = make_variant_vt_ref(safe_n6, automation.VT_R8) + + safe_n7 = make_safe_array_double(1) + n7 = make_variant_vt_ref(safe_n7, automation.VT_R8) + + safe_n8 = make_safe_array_double(1) + n8 = make_variant_vt_ref(safe_n8, automation.VT_R8) + + safe_n9 = make_safe_array_double(1) + n9 = make_variant_vt_ref(safe_n9, automation.VT_R8) + + safe_n10 = make_safe_array_double(1) + n10 = make_variant_vt_ref(safe_n10, automation.VT_R8) + + ret_val = self._property.GetSectionPropertyValues(ref_no,n1,n2,n3,n4,n5,n6,n7,n8,n9,n10) - def make_safe_array_long(array): - size = len(array) - return automation._midlSAFEARRAY(ctypes.c_long).create(array) + a1 = round(n1.value[0]*1000)/1000 + a2 = round(n2.value[0]*1000)/1000 + a3 = round(n3.value[0]*1000000)/1000000 + a4 = round(n4.value[0]*1000000)/1000000 + a5 = round(n5.value[0]*1000000)/1000000 + a6 = round(n6.value[0]*1000000)/1000000 + a7 = round(n7.value[0]*1000)/1000 + a8 = round(n8.value[0]*1000)/1000 + a9 = round(n9.value[0]*1000)/1000 + a10 = round(n10.value[0]*1000)/1000 - # Crear SAFEARRAY para 'beamNo' - safe_list = make_safe_array_long(beamNo) - beamNo = make_variant_vt_ref(safe_list, automation.VT_ARRAY | automation.VT_I4) + return {'Is_Ref':ret_val, + 'WID': a1, + 'DEP': a2, + 'Ax': a3, + 'Ay': a4, + 'Az': a5, + 'Ix': a6, + 'Iy': a7, + 'Iz': a8, + 'Tf': a9, + 'Tw': a10 + } + + def IsRelease(self, memb): + """ + Checks if a member has any releases specified at its start or end node. + *Note: The accuracy of this function depends on `GetMemberReleaseSpecEx` returning a tuple of 6 release values for each end. If `GetMemberReleaseSpecEx` only returns a single integer (e.g., FX status), the comparison `rel_i == (0,0,0,0,0,0)` will likely not work as intended.* + """ + rel_i = self.GetMemberReleaseSpecEx(memb, start=True) + rel_j = self.GetMemberReleaseSpecEx(memb,start=False) - retval= self._property.AssignMaterialToMember(material_name, beamNo) + if rel_i == (0,0,0,0,0,0) and rel_j == (0,0,0,0,0,0): + return False + else: + return True - return retval \ No newline at end of file diff --git a/openstaad/root.py b/openstaad/root.py index 38926f6..6096ed3 100644 --- a/openstaad/root.py +++ b/openstaad/root.py @@ -8,21 +8,25 @@ def __init__(self): staad = client.GetActiveObject("StaadPro.OpenSTAAD") self._root = staad - self._functions = ['GetAnalysisStatus', - 'GetApplicationVersion', - 'GetBaseUnit', - 'GetSTAADFile', - 'GetSTAADFileFolder', - 'GetInputUnitForForce', - 'GetInputUnitForLength', - 'NewSTAADFile', - 'Analyze', - 'SaveModel' + self._functions = [ + 'Analyze', + 'GetAnalysisStatus', + 'GetApplicationVersion', + 'GetBaseUnit', + 'GetInputUnitForForce', + 'GetInputUnitForLength', + 'GetSTAADFile', + 'GetSTAADFileFolder', + 'NewSTAADFile', + 'SaveModel' ] for function_name in self._functions: self._root._FlagAsMethod(function_name) + def Analyze(self): + self._root.Analyze() + def GetAnalysisStatus(self): """ Get analysis status for the open STAAD Model. @@ -246,9 +250,8 @@ def NewSTAADFile(self, file_name: str = "Structure1.STD",len_unit: int = 4, forc path = os.path.join(folder_path, file_name) self._root.NewSTAADFile(path,len_unit,force_unit) - - def Analyze(self): - self._root.Analyze() def SaveModel(self,silent:int): - self._root.SaveModel(silent) \ No newline at end of file + self._root.SaveModel(silent) + + diff --git a/openstaad/support.py b/openstaad/support.py index 9799756..ede0b6c 100644 --- a/openstaad/support.py +++ b/openstaad/support.py @@ -9,31 +9,45 @@ def __init__(self): self._support = self._staad.Support self._functions= [ + 'AssignSupportToNode', 'CreateSupportFixed', 'CreateSupportPinned', - 'AssignSupportToNode', 'GetSupportCount', - 'GetSupportNodes' + 'GetSupportNodes', + 'GetSupportType' ] for function_name in self._functions: self._support._FlagAsMethod(function_name) - ## SUPPORT FUNCTIONS + def AssignSupportToNode(self,NoNode:int,Support_type_ID:int): + """ + Assigns the specified support to node(s). + """ + self._support.AssignSupportToNode(NoNode,Support_type_ID) def CreateSupportFixed(self): + """ + Creates a fully fixed support. + """ self._support.CreateSupportFixed() def CreateSupportPinned(self): + """ + Creates a pinned support (i.e., free to rotate about local y and z axis, fixed in all other degrees of freedom). + """ self._support.CreateSupportPinned() - def AssignSupportToNode(self,NoNode:int,Support_type_ID:int): - self._support.AssignSupportToNode(NoNode,Support_type_ID) - def GetSupportCount(self): + """ + Gets the total number of supported nodes exist in the current structure. + """ return (self._support.GetSupportCount()) - + def GetSupportNodes(self): + """ + Gets all supported nodes in an array. + """ n_supports = self._support.GetSupportCount() safe_list = make_safe_array_long(n_supports) @@ -41,4 +55,11 @@ def GetSupportNodes(self): self._support.GetSupportNodes(lista) - return (lista[0]) \ No newline at end of file + return (lista[0]) + + def GetSupportType(self,node:int): + """ + Gets the support type for the specified node. + """ + return self._support.GetSupportType(node) + \ No newline at end of file diff --git a/openstaad/tools.py b/openstaad/tools.py index 3740b8c..d2b02fa 100644 --- a/openstaad/tools.py +++ b/openstaad/tools.py @@ -34,6 +34,5 @@ def make_safe_array_long_input(lista): 'table':'Table', 'view':'View', 'output':'Output', - 'command':'Command', - 'design':'Design' + 'commands':'Commands' } \ No newline at end of file diff --git a/openstaad/view.py b/openstaad/view.py index 1c7d617..496cb7e 100644 --- a/openstaad/view.py +++ b/openstaad/view.py @@ -10,115 +10,195 @@ def __init__(self): self._view = self._staad.View self._geometry = Geometry() - self._functions= [ - "RefreshView", - "ShowAllMembers", + self._functions = [ + "GetBeamsInView", + "GetNoOfBeamsInView", "HideAllMembers", - "ZoomExtentsMainView", - "ShowMembers", "HideMember", "HideMembers", + "RefreshView", + "SelectMembersParallelTo", + "ShowAllMembers", "ShowBack", "ShowBottom", "ShowFront", "ShowIsometric", "ShowLeft", + "ShowMembers", "ShowPlan", "ShowRight", "SpinLeft", "SpinRight", "ZoomAll", - "SelectMembersParallelTo" + "ZoomExtentsMainView" ] for function_name in self._functions: self._view._FlagAsMethod(function_name) - def RefreshView(self): - self._view.RefreshView() + def GetBeamsInView(self): + """ + Get a list of beam IDs currently visible in the view. + """ + beams=self._view.GetNoOfBeamsInView() + safe_list = make_safe_array_long(beams) + lista = make_variant_vt_ref(safe_list, automation.VT_ARRAY | automation.VT_I4) - def ShowAllMembers(self): - self._view.ShowAllMembers() + self._view.GetBeamsInView(lista) + + return (lista[0]) + + def GetNoOfBeamsInView(self): + """ + Get the number of beams currently visible in the view. + """ + return self._view.GetNoOfBeamsInView() def HideAllMembers(self): + """ + Hide all members from the view. + """ self._view.HideAllMembers() - - def ZoomExtentsMainView(self): - self._view.ZoomExtentsMainView() - - def ShowMembers(self,NMembers,NaMemberNos): - safe_list = make_safe_array_long_input(NaMemberNos) - lista_variant = make_variant_vt_ref(safe_list, automation.VT_ARRAY | automation.VT_I4) - - self._view.ShowAllMembers() - self._view.HideAllMembers() - self._geometry.ClearMemberSelection() - self._view.ShowMembers(NMembers,lista_variant) - self._view.ShowIsometric() - self._view.ZoomExtentsMainView() - self._view.RefreshView() - - def HideMember(self,IDMember): + + def HideMember(self,IDMember:int): + """ + Hide a single member from the view. + """ self._view.HideMember(IDMember) - # self._view.RefreshView() + self._view.RefreshView() - def HideMembers(self,NMembers,NaMemberNos): + def HideMembers(self,NaMemberNos:list): + """ + Hide multiple members from the view. + """ + Nmembers=len(NaMemberNos) safe_list = make_safe_array_long_input(NaMemberNos) lista_variant = make_variant_vt_ref(safe_list, automation.VT_ARRAY | automation.VT_I4) - - self._view.HideMembers(NMembers,lista_variant) + + self._view.HideMembers(Nmembers,lista_variant) self._view.RefreshView() + + def RefreshView(self): + """ + Refresh the viewing window. + """ + self._view.RefreshView() + + def SelectMembersParallelTo(self,axis:str="X"): + """ + Select members parallel to the specified axis. + """ + self._view.SelectMembersParallelTo(axis) + def ShowAllMembers(self): + """ + Show all members. + """ + self._view.ShowAllMembers() + def ShowBack(self): + """ + Show the back view of the model. + """ self._view.ShowBack() self._view.RefreshView() self._view.ZoomExtentsMainView() def ShowBottom(self): + """ + Show the bottom view of the model. + """ self._view.ShowBottom() self._view.RefreshView() self._view.ZoomExtentsMainView() def ShowFront(self): + """ + Show the front view of the model. + """ self._view.ShowFront() self._view.RefreshView() self._view.ZoomExtentsMainView() def ShowIsometric(self): + """ + Show an isometric view of the model. + """ self._view.ShowIsometric() self._view.RefreshView() self._view.ZoomExtentsMainView() def ShowLeft(self): + """ + Show the left view of the model. + """ self._view.ShowLeft() self._view.RefreshView() self._view.ZoomExtentsMainView() + def ShowMembers(self,NaMemberNos:list): + """ + Show only the specified members in the model view. + """ + Nmembers=len(NaMemberNos) + safe_list = make_safe_array_long_input(NaMemberNos) + lista_variant = make_variant_vt_ref(safe_list, automation.VT_ARRAY | automation.VT_I4) + + self._view.ShowAllMembers() + self._view.HideAllMembers() + self._geometry.ClearMemberSelection() + self._view.ShowMembers(Nmembers,lista_variant) + self._view.ShowIsometric() + self._view.ZoomExtentsMainView() + self._view.RefreshView() + def ShowPlan(self): + """ + Show the top plan view of the model. + """ self._view.ShowPlan() self._view.RefreshView() self._view.ZoomExtentsMainView() def ShowRight(self): + """ + Show the right view of the model. + """ self._view.ShowRight() self._view.RefreshView() self._view.ZoomExtentsMainView() - def SpinLeft(self,Degrees): + def SpinLeft(self,Degrees:float): + """ + Spin the model view to the left by a specified degree. + """ Degrees = float(Degrees) self._view.SpinLeft(Degrees) self._view.RefreshView() self._view.ZoomExtentsMainView() - def SpinRight(self,Degrees): + def SpinRight(self,Degrees:float): + """ + Spin the model view to the right by a specified degree. + """ Degrees = float(Degrees) self._view.SpinRight(Degrees) self._view.RefreshView() self._view.ZoomExtentsMainView() def ZoomAll(self): + """ + Zoom all objects in the view. + """ self._view.ZoomAll() - def SelectMembersParallelTo(self,axis): - self._view.SelectMembersParallelTo(axis) + def ZoomExtentsMainView(self): + """ + Display the whole structure. + """ + self._view.ZoomExtentsMainView() + + + +