Coverage for bim2sim/kernel/ifc_file.py: 100%

46 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-03-12 17:09 +0000

1import logging 

2 

3from pathlib import Path 

4from ifcopenshell import file 

5 

6from bim2sim.elements.mapping.finder import TemplateFinder 

7from bim2sim.elements.mapping.units import parse_ifc 

8from bim2sim.elements.mapping import ifc2python 

9from bim2sim.utilities.types import IFCDomain 

10 

11logger = logging.getLogger(__name__) 

12 

13 

14class IfcFileClass: 

15 """Combine IfcOpenShell file instance, finder and units together. 

16 

17 Especially if we handle multiple IFC files this dataclass helps us to keep 

18 track which finder and units belong to which ifc file. 

19 

20 Args: 

21 ifc_path: Pathlib object that points to ifc file 

22 reset_guids: Boolean that determine if GUIDs should be reset 

23 ifc_domain: Domain of the given ifc file if this is known 

24 """ 

25 

26 def __init__( 

27 self, 

28 ifc_path: Path, 

29 reset_guids: bool = False, 

30 ifc_domain: IFCDomain = None): 

31 self.ifc_file_name = ifc_path.name 

32 self.file = self.load_ifcopenshell_file(ifc_path) 

33 self.finder = None 

34 self.ifc_units = self.get_ifc_units() 

35 self.domain = ifc_domain if ifc_domain else IFCDomain.unknown 

36 self.schema = self.file.schema 

37 if reset_guids: 

38 self.file = ifc2python.reset_guids(self.file) 

39 

40 def initialize_finder(self, finder_path): 

41 self.finder = TemplateFinder() 

42 yield from self.finder.initialize(self.file) 

43 if finder_path: 

44 self.finder.load(finder_path) 

45 

46 @staticmethod 

47 def load_ifcopenshell_file(ifc_path) -> file: 

48 """Loads the IfcOpenShell file instance""" 

49 ifc_file = ifc2python.load_ifc(ifc_path) 

50 return ifc_file 

51 

52 def get_ifc_units(self) -> dict: 

53 """Returns dict to translate IFC units to pint units 

54 

55 To use units from IFC we get all unit definitions from the ifc and their 

56 corresponding measurement elements and map them to pint units. 

57 

58 Returns: 

59 dict where key is the IfcMeasurement and value the pint unit 

60 definition. e.g. 'IfcLengthMeasure': meter 

61 """ 

62 logger.info(f"Initializing units for IFC file: {self.ifc_file_name}") 

63 unit_assignment = self.file.by_type('IfcUnitAssignment') 

64 

65 ifc_units = {} 

66 

67 for unit_entity in unit_assignment[0].Units: 

68 try: 

69 if hasattr(unit_entity, 'UnitType'): 

70 key = 'Ifc{}'.format( 

71 unit_entity.UnitType.capitalize().replace('unit', 

72 'Measure')) 

73 pos_key = 'IfcPositive{}'.format( 

74 unit_entity.UnitType.capitalize().replace('unit', 

75 'Measure')) 

76 elif hasattr(unit_entity, 'Currency'): 

77 key = 'IfcMonetaryMeasure' 

78 unit = parse_ifc(unit_entity) 

79 ifc_units[key] = unit 

80 if pos_key: 

81 ifc_units[pos_key] = unit 

82 except: 

83 logger.warning(f"Failed to parse {unit_entity}") 

84 ifc_units = {k.lower(): v for k, v in ifc_units.items()} 

85 return ifc_units