diff --git a/RFEM/Tools/centreOfGravityAndObjectInfo.py b/RFEM/Tools/centreOfGravityAndObjectInfo.py new file mode 100644 index 00000000..4340f860 --- /dev/null +++ b/RFEM/Tools/centreOfGravityAndObjectInfo.py @@ -0,0 +1,132 @@ +from RFEM.initModel import * +from RFEM.enums import * + +class ObjectInformation(): + + def CentreOfGravity(self, + type = ObjectTypes.E_OBJECT_TYPE_MEMBER, + parent_no = 0, + no: int = 1, + coord: str = 'X'): + + ''' + This function returns the centre of gravity position (X, Y or Z) for a selected object. + + Args: + type (enum): Object Type + parent_no (int): Object Parent Number + Note: + (1) A geometric object has, in general, a parent_no = 0 + (2) The parent_no parameter becomes significant for example with loads + no (int): The Object Tag + coord (str): Desired global basis vector component of the Centre of Gravity (i.e. X, Y or Z) + ''' + + self.object_type = type + self.no = no + self.parent_no = parent_no + + result = ObjectInformation.__BuildResultsArray(self) + + if coord == 'X' or coord.lstrip().rstrip().upper() == 'X': + return result['section'][0].rows[0][0].value + elif coord == 'Y' or coord.lstrip().rstrip().upper() == 'Y': + return result['section'][0].rows[0][1].value + elif coord == 'Z' or coord.lstrip().rstrip().upper() == 'Z': + return result['section'][0].rows[0][2].value + else: + raise Exception ('WARNING: The desired Coordinate input not requested. Please provide either "X", "Y" or "Z"') + + def MemberInformation(self, + no: int = 1, + information = SelectedObjectInformation.LENGTH): + + ''' + This function returns further information associated with a member. + + Args: + no (int): Member Tag + information (enum): Desired Information (Length / Volume / Mass) + ''' + + if information.name == 'AREA': + raise Exception ('WARNING: Area information is only relevant for Surface and Volume Information.') + + self.object_type = ObjectTypes.E_OBJECT_TYPE_MEMBER + self.no = no + self.parent_no = 0 + self.information = information + self.row_key = 2 + self.result = ObjectInformation.__BuildResultsArray(self) + + return ObjectInformation.__AreaVolumeMassInformationLength(self) + + def SurfaceInformation(self, + no: int = 1, + information = SelectedObjectInformation.AREA): + + ''' + This function returns further information associated with a surface. + + Args: + no (int): Surface Tag + information (enum): Desired Information (Area / Volume / Mass) + ''' + + if information.name == 'LENGTH': + raise Exception ('WARNING: Length information is only relevant for Member Information.') + + self.object_type = ObjectTypes.E_OBJECT_TYPE_SURFACE + self.no = no + self.parent_no = 0 + self.information = information + self.row_key = 3 + self.result = ObjectInformation.__BuildResultsArray(self) + + return ObjectInformation.__AreaVolumeMassInformationLength(self) + + def SolidInformation(self, + no: int = 1, + information = SelectedObjectInformation.AREA): + + ''' + This function returns further information associated with a solid. + + Args: + no (int): Solid Tag + information (enum): Desired Information (Area / Volume / Mass) + ''' + + if information.name == 'LENGTH': + raise Exception ('WARNING: Length information is only relevant for Member Information.') + + self.object_type = ObjectTypes.E_OBJECT_TYPE_SOLID + self.no = no + self.parent_no = 0 + self.information = information + self.row_key = 4 + self.result = ObjectInformation.__BuildResultsArray(self) + + return ObjectInformation.__AreaVolumeMassInformationLength(self) + + def __BuildResultsArray(self): + + elements = clientModel.factory.create('ns0:array_of_get_center_of_gravity_and_objects_info_elements_type') + clientObject = clientModel.factory.create('ns0:get_center_of_gravity_and_objects_info_element_type') + clientObject.parent_no = self.parent_no + clientObject.no = self.no + clientObject.type = self.object_type.name + elements.element.append(clientObject) + result = clientModel.service.get_center_of_gravity_and_objects_info(elements) + result = clientModel.dict(result) + + return result + + def __AreaVolumeMassInformationLength(self): + + if self.information.name == "LENGTH" or self.information.name == "AREA": + return self.result['section'][self.row_key].rows[0][0].value + elif self.information.name == "VOLUME": + return self.result['section'][self.row_key].rows[0][1].value + elif self.information.name == "MASS": + return self.result['section'][self.row_key].rows[0][2].value \ No newline at end of file diff --git a/RFEM/enums.py b/RFEM/enums.py index 3e892462..6dbc756e 100644 --- a/RFEM/enums.py +++ b/RFEM/enums.py @@ -706,6 +706,11 @@ class export_to_ifc_export_type(Enum): E_EXPORT_IFC4_REFERENCE_VIEW, E_EXPORT_IFC4_STRUCTURAL_ANALYSIS_VIEW = range(2) +class SelectedObjectInformation(Enum): + ''' + Information About Members | Enum + ''' + LENGTH, VOLUME, MASS, AREA = range(4) class GlobalAxesOrientationType(Enum): ''' Model Settings and Options Global Axes Orientation Type diff --git a/UnitTests/test_objectInformation.py b/UnitTests/test_objectInformation.py new file mode 100644 index 00000000..74ce3e0d --- /dev/null +++ b/UnitTests/test_objectInformation.py @@ -0,0 +1,86 @@ +import sys +sys.path.append(".") + +# Import the relevant Libraries +from os import name +from RFEM.enums import * +from RFEM.dataTypes import * +from RFEM.initModel import * +from RFEM.BasicObjects.material import * +from RFEM.BasicObjects.section import * +from RFEM.BasicObjects.thickness import * +from RFEM.BasicObjects.node import * +from RFEM.BasicObjects.line import * +from RFEM.BasicObjects.member import * +from RFEM.BasicObjects.surface import * +from RFEM.BasicObjects.solid import * +from RFEM.Tools.centreOfGravityAndObjectInfo import * + +def test_centre_of_gravity(): + + clientModel.service.begin_modification('new') + + x1, y1, z1, = 0, 0, 0 + x2, y2, z2 = 4, 10, -6 + Node(1, x1, y1, z1), Node(2, x2, y2, z2) + Material(1, 'S235') + Section() + Member(1, start_node_no= 1, end_node_no= 2) + + clientModel.service.finish_modification() + + CoG_X = (x2 - x1) / 2 + CoG_Y = (y2 - y1) / 2 + CoG_Z = (z2 - z1) / 2 + L = round(sqrt((x2 - x1)**2 + (y2 - y1)**2 + (z2 - z1)**2),3) + + assert CoG_X == ObjectInformation.CentreOfGravity(ObjectInformation, coord= 'X') + assert CoG_Y == ObjectInformation.CentreOfGravity(ObjectInformation, coord= 'Y') + assert CoG_Z == ObjectInformation.CentreOfGravity(ObjectInformation, coord= 'Z') + +def test_member_information(): + + clientModel.service.begin_modification('new') + + x1, y1, z1, = 0, 0, 0 + x2, y2, z2 = 4, 10, -6 + Node(1, x1, y1, z1), Node(2, x2, y2, z2) + Material(1, 'S235') + Section() + Member(1, start_node_no= 1, end_node_no= 2) + + clientModel.service.finish_modification() + + L = sqrt((x2 - x1)**2 + (y2 - y1)**2 + (z2 - z1)**2) + A = 53.80 / (100 * 100) + V = L * A + M = (V * 7850) / 1000 + + assert round(L,3) == ObjectInformation.MemberInformation(ObjectInformation, information= SelectedObjectInformation.LENGTH) + assert round(V,3) == ObjectInformation.MemberInformation(ObjectInformation, information= SelectedObjectInformation.VOLUME) + assert round(M,3) == ObjectInformation.MemberInformation(ObjectInformation, information= SelectedObjectInformation.MASS) + +def test_surface_information(): + + clientModel.service.begin_modification('new') + + x1, y1, z1 = 0 , 0, 0 + x2, y2, z2 = 10, 0, 0 + x3, y3, z3 = 10, 15, 0 + x4, y4, z4 = 0, 15, 0 + + Node(1, x1, y1, z1), Node(2, x2, y2, z2), Node(3, x3, y3, z3), Node(4, x4, y4, z4) + Line(1, '1 2'), Line(2, '2 3'), Line(3, '3 4'), Line(4, '4 1') + Material(2, name='C30/37') + Thickness(material_no= 2) + Surface() + + clientModel.service.finish_modification() + + A = (x2 - x1) * (y4 - y1) + V = A * 0.2 + M = (V * 2500) / 1000 + + assert round(A,3) == ObjectInformation.SurfaceInformation(ObjectInformation, information= SelectedObjectInformation.AREA) + assert round(V,3) == ObjectInformation.SurfaceInformation(ObjectInformation, information= SelectedObjectInformation.VOLUME) + assert round(M,3) == ObjectInformation.SurfaceInformation(ObjectInformation, information= SelectedObjectInformation.MASS) \ No newline at end of file