Coverage for bim2sim / utilities / visualize_spaces.py: 0%

61 statements  

« prev     ^ index     » next       coverage.py v7.13.0, created at 2025-12-18 09:34 +0000

1""" 

2Thermal Zone Visualization Module 

3================================= 

4 

5This module provides functionality to visualize thermal zones and save the 

6output as an image. It includes functions to convert RGB values to 

7OCC-compatible colors and to generate visualizations of thermal zones grouped 

8by various criteria. 

9 

10Example: 

11 For an example, please see e4_visualize_zone_binding.py in PluginTEASER. 

12 

13Functions: 

14 rgb_color(rgb): Returns an OCC viewer compatible color quantity based on 

15 r,g,b values. 

16 visualize_zones(zone_dict, folder_structure): Visualizes the thermal 

17 zones and saves the picture as a .png. 

18 

19Notes: 

20 Any additional information about the module, its purpose, and its usage 

21 can be included here. 

22""" 

23import logging 

24from pathlib import Path 

25from typing import Union 

26 

27import numpy as np 

28import ifcopenshell.geom 

29from OCC.Display.SimpleGui import init_display 

30from OCC.Core.Quantity import Quantity_Color, Quantity_TOC_RGB 

31from PIL import Image, ImageDraw 

32 

33from bim2sim.elements.bps_elements import ThermalZone 

34 

35logger = logging.getLogger(__name__) 

36 

37 

38def rgb_color(rgb) -> Quantity_Color: 

39 """Returns a OCC viewer compatible color quantity based on r,g,b values. 

40 

41 Args: 

42 rgb: must be a tuple with 3 values [0,1]. e.g. (0, 0.5, 0.7) 

43 

44 Returns: 

45 Quantity_Color object which is compatible with with the OCC viewer. 

46 """ 

47 return Quantity_Color(rgb[0], rgb[1], rgb[2], Quantity_TOC_RGB) 

48 

49 

50def visualize_zones( 

51 thermal_zones: list[ThermalZone], 

52 path: Path, 

53 filename: Union[str, None] = None): 

54 """Visualizes the ThermalZone element entities and saves the picture as 

55 a .png. Fetches the ThermalZone which are grouped before and creates an 

56 abstract building image, where each grouped zone has its own color. 

57 Afterwards, a legend is added with zone names and corresponding colors. 

58 The file is exported as .png to the export folder. 

59 

60 Args: 

61 thermal_zones: list of ThermalZone and AggregatedThermalZone instances 

62 path: pathlib Path where image is exported to 

63 filename: str of filename 

64 

65 Returns: 

66 No return value, image is saved directly. 

67 """ 

68 settings = ifcopenshell.geom.settings() 

69 settings.set(settings.USE_PYTHON_OPENCASCADE, True) 

70 settings.set(settings.USE_WORLD_COORDS, True) 

71 settings.set(settings.PRECISION, 1e-6) 

72 settings.set( 

73 "dimensionality", 

74 ifcopenshell.ifcopenshell_wrapper.CURVES_SURFACES_AND_SOLIDS) # 2 

75 # settings.set(settings.EXCLUDE_SOLIDS_AND_SURFACES, False) 

76 # settings.set(settings.INCLUDE_CURVES, True) 

77 

78 # Call init_display 

79 # TODO this messes with the logger, but method like below doesn't work 

80 # with open(os.devnull, 'w') as devnull: 

81 display, start_display, add_menu, add_function_to_menu = init_display( 

82 display_triedron=False, background_gradient_color1=3 * [255], 

83 background_gradient_color2=3 * [255], size=(1920, 1080)) 

84 

85 legend = {} 

86 num = 1 

87 for tz in thermal_zones: 

88 name = tz.name 

89 rgb_tuple = tuple((np.random.choice(range(256), size=3))) 

90 rgb_tuple_norm = tuple([round(x / 256, 2) for x in rgb_tuple]) 

91 if name in list(legend.keys()): 

92 name = name + ' ' + str(num) 

93 num += 1 

94 legend[name] = rgb_tuple 

95 color = rgb_color(rgb_tuple_norm) 

96 # handle AggregatedThermalZone 

97 if hasattr(tz, "elements"): 

98 zones = tz.elements 

99 for zone in zones: 

100 display.DisplayShape(zone.space_shape, update=True, 

101 color=color, transparency=0.5) 

102 # handle normal ThermalZone 

103 else: 

104 display.DisplayShape(tz.space_shape, update=True, 

105 color=color, transparency=0.5) 

106 sorted_legend = {} 

107 for k in sorted(legend, key=len, reverse=False): 

108 sorted_legend[k] = legend[k] 

109 

110 nr_zones = len(thermal_zones) 

111 if not filename: 

112 filename = f"zoning_visualization_{str(nr_zones)}_zones.png" 

113 

114 save_path = Path(path / filename) 

115 display.View.Dump(str(save_path)) 

116 

117 text_size = 25 

118 zone_image = Image.open(save_path) 

119 image_editable = ImageDraw.Draw(zone_image) 

120 zone_image_size_y = zone_image.size[1] 

121 

122 rec_size = 20 

123 space = 30 

124 buffer = 10 

125 

126 legend_height = len(sorted_legend) * (text_size + space / 3) + buffer 

127 x0 = 0 

128 rec_to_text_spacing = 10 

129 y0 = zone_image_size_y - legend_height 

130 

131 for zone_name, color in sorted_legend.items(): 

132 xy = [(x0 + rec_to_text_spacing, y0), 

133 (x0 + + rec_to_text_spacing + rec_size, y0 + rec_size)] 

134 image_editable.rectangle(xy, fill=color, outline=None, width=text_size) 

135 image_editable.text( 

136 (x0 + rec_to_text_spacing + rec_size + 10, y0), zone_name, 

137 (0, 0, 0)) 

138 y0 += space 

139 

140 zone_image.save(save_path) 

141 logger.info(f"Exported visualization of combined ThermalZone instances to " 

142 f"{save_path}.")