diff --git a/FreeCAD/BIMxBEM/freecad/bem/bem_xml.py b/FreeCAD/BIMxBEM/freecad/bem/bem_xml.py index 98aa849..b773e6f 100644 --- a/FreeCAD/BIMxBEM/freecad/bem/bem_xml.py +++ b/FreeCAD/BIMxBEM/freecad/bem/bem_xml.py @@ -1,189 +1,204 @@ # coding: utf8 """This module write boundaries informations to an xml format for BEM software use © All rights reserved. ECOLE POLYTECHNIQUE FEDERALE DE LAUSANNE, Switzerland, Laboratory CNPA, 2019-2020 See the LICENSE.TXT file for more details. Author : Cyril Waechter """ import xml.etree.ElementTree as ET from freecad.bem import materials SCALE = 1000 class BEMxml: """Contains methods to write each kind of object to BEMxml""" def __init__(self): self.root = ET.Element("bimbem") self.tree = ET.ElementTree(self.root) self.projects = ET.SubElement(self.root, "Projects") self.spaces = ET.SubElement(self.root, "Spaces") self.boundaries = ET.SubElement(self.root, "Boundaries") self.building_elements = ET.SubElement(self.root, "BuildingElements") self.materials = ET.SubElement(self.root, "Materials") @staticmethod def write_root_attrib(xml_element, fc_object): ET.SubElement(xml_element, "Id").text = str(fc_object.Id) ET.SubElement(xml_element, "GlobalId").text = fc_object.GlobalId ET.SubElement(xml_element, "Name").text = fc_object.Name ET.SubElement(xml_element, "Description").text = fc_object.Description ET.SubElement(xml_element, "IfcType").text = fc_object.IfcType def write_project(self, fc_object): project = ET.SubElement(self.projects, "Project") self.write_root_attrib(project, fc_object) ET.SubElement(project, "LongName").text = fc_object.LongName north = ET.SubElement(project, "TrueNorth") ET.SubElement(north, "point", vector_to_dict(fc_object.TrueNorth)) wcs = ET.SubElement(project, "WorldCoordinateSystem") ET.SubElement(wcs, "point", vector_to_dict(fc_object.WorldCoordinateSystem)) self.sites = ET.SubElement(project, "Sites") for site in fc_object.Group: self.write_site(site) def write_site(self, fc_object): site = ET.SubElement(self.sites, "Site") self.write_root_attrib(site, fc_object) self.buildings = ET.SubElement(site, "Buildings") for building in fc_object.Group: self.write_building(building) def write_building(self, fc_object): site = ET.SubElement(self.buildings, "Building") self.write_root_attrib(site, fc_object) self.storeys = ET.SubElement(site, "Storeys") for storey in fc_object.Group: self.write_storey(storey) def write_storey(self, fc_object): storey = ET.SubElement(self.storeys, "Storey") self.write_root_attrib(storey, fc_object) spaces = ET.SubElement(storey, "Spaces") for space in fc_object.Group: ET.SubElement(spaces, "Space").text = str(space.Id) def write_space(self, fc_object): space = ET.SubElement(self.spaces, "Space") self.write_root_attrib(space, fc_object) boundaries = ET.SubElement(space, "Boundaries") for boundary in fc_object.SecondLevel.Group: ET.SubElement(boundaries, "Boundary").text = str(boundary.Id) def write_boundary(self, fc_object): boundary = ET.SubElement(self.boundaries, "Boundary") self.write_root_attrib(boundary, fc_object) id_references = ( "CorrespondingBoundary", "RelatedBuildingElement", ) for name in id_references: self.append_id_element(boundary, fc_object, name) text_references = ( "InternalOrExternalBoundary", "PhysicalOrVirtualBoundary", "LesoType" ) for name in text_references: self.append_text_element(boundary, fc_object, name) ET.SubElement(boundary, "ParentBoundary").text = ( str(fc_object.ParentBoundary) if fc_object.ParentBoundary else "" ) ET.SubElement(boundary, "RelatingSpace").text = ( str(fc_object.RelatingSpace) if fc_object.RelatingSpace else "" ) inner_boundaries = ET.SubElement(boundary, "InnerBoundaries") for fc_inner_b in fc_object.InnerBoundaries: ET.SubElement(inner_boundaries, "InnerBoundary").text = str(fc_inner_b.Id) self.write_shape(boundary, fc_object) is_hosted = fc_object.IsHosted ET.SubElement(boundary, "IsHosted").text = "true" if is_hosted else "false" if not is_hosted and fc_object.PhysicalOrVirtualBoundary != "VIRTUAL": for geo_type in ("SIA_Interior", "SIA_Exterior"): geo = ET.SubElement(boundary, geo_type) fc_geo = getattr(fc_object, geo_type) self.write_shape(geo, fc_geo) def write_building_elements(self, fc_object): building_element = ET.SubElement(self.building_elements, "BuildingElement") self.write_root_attrib(building_element, fc_object) ET.SubElement(building_element, "Thickness").text = str( fc_object.Thickness.Value / SCALE ) boundaries = ET.SubElement(building_element, "ProvidesBoundaries") for element_id in fc_object.ProvidesBoundaries: ET.SubElement(boundaries, "Id").text = str(element_id) if fc_object.Material: ET.SubElement(building_element, "Material").text = str(fc_object.Material.Id or "") def write_material(self, fc_object): if isinstance(fc_object.Proxy, materials.Material): properties = [p for l in materials.Material.pset_dict.values() for p in l] - material_dict = {p: getattr(fc_object, p) for p in properties} - material = ET.SubElement(self.materials, "Material", material_dict) + properties[0:0] = ["Category"] + material = ET.SubElement(self.materials, "Material") elif isinstance(fc_object.Proxy, materials.LayerSet): - layer_set = ET.SubElement(self.materials, "LayerSet") + material = ET.SubElement(self.materials, "LayerSet") + properties = ["TotalThickness"] + layers = ET.SubElement(material, "Layers") + for fc_material, thickness in zip(fc_object.MaterialLayers, fc_object.Thicknesses): + layer = ET.SubElement(layers, "Layer") + ET.SubElement(layer, "Id").text = str(fc_material.Id) + ET.SubElement(layer, "Thickness").text = str(thickness) elif isinstance(fc_object.Proxy, materials.ConstituentSet): - constituent_set = ET.SubElement(self.materials, "ConstituentSet") + material = ET.SubElement(self.materials, "ConstituentSet") + properties = [] + for fc_material, category, fraction in zip(fc_object.MaterialLayers, fc_object.Categories, fc_object.Fractions): + layer = ET.SubElement(layers, "Layer") + ET.SubElement(layer, "Id").text = str(fc_material.Id) + ET.SubElement(layer, "Category").text = str(category) + ET.SubElement(layer, "Fraction").text = str(fraction) + properties[0:0] = ["Id", "IfcName", "Description"] + for prop in properties: + ET.SubElement(material, prop).text = str(getattr(fc_object, prop)) @staticmethod def write_shape(xml_element, fc_object): geom = ET.SubElement(xml_element, "geom") for wire in fc_object.Proxy.get_wires(fc_object): polygon = ET.SubElement(geom, "Polygon") for vertex in wire.Vertexes: ET.SubElement(polygon, "point", vector_to_dict(vertex.Point)) ET.SubElement(xml_element, "Area").text = fc_area_to_si_xml(fc_object.Area) ET.SubElement(xml_element, "AreaWithHosted").text = fc_area_to_si_xml( fc_object.AreaWithHosted ) @staticmethod def append_id_element(xml_element, fc_object, name): value = getattr(fc_object, name) ET.SubElement(xml_element, name).text = str(value.Id) if value else "" @staticmethod def append_text_element(xml_element, fc_object, name): ET.SubElement(xml_element, name).text = getattr(fc_object, name) def write_to_file(self, full_path): self.tree.write(full_path, encoding="UTF-8", xml_declaration=True) def tostring(self): # Return a bytes # return ET.tostring(self.root, encoding="utf8", method="xml") # Return a string return ET.tostring(self.root, encoding="unicode") def vector_to_dict(vector): """Convert a FreeCAD.Vector into a dict to write it as attribute in xml""" return {key: str(getattr(vector, key) / SCALE) for key in ("x", "y", "z")} def fc_area_to_si_xml(fc_area): return str(fc_area.getValueAs("m^2")) if __name__ == "__main__": OUTPUT = BEMxml() OUTPUT.write_project(None) OUTPUT_FILE = "output.xml" OUTPUT.tree.write(OUTPUT_FILE, encoding="UTF-8", xml_declaration=True)