From f91f44cd4a2c7edd094f62228deb9bb799cca8e8 Mon Sep 17 00:00:00 2001 From: Chirag Singh Date: Fri, 3 Apr 2026 01:30:59 +0530 Subject: [PATCH] Light/ Ran black formatting --- src/bonsai/bonsai/bim/module/light/export.py | 24 ++- src/bonsai/bonsai/bim/module/light/ies.py | 1 - src/bonsai/bonsai/bim/module/light/prepare.py | 157 ++++++++++++------ src/bonsai/bonsai/bim/module/light/render.py | 24 ++- src/bonsai/bonsai/bim/module/light/ui.py | 12 +- 5 files changed, 147 insertions(+), 71 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/light/export.py b/src/bonsai/bonsai/bim/module/light/export.py index 7ff9fd493f..dd93f8a6e1 100644 --- a/src/bonsai/bonsai/bim/module/light/export.py +++ b/src/bonsai/bonsai/bim/module/light/export.py @@ -162,12 +162,12 @@ class ExportOBJ(bpy.types.Operator): # exported by _export_linked_models() via the IFC serializer. instance_parents = set() for obj in bpy.data.objects: - if obj.instance_type == 'COLLECTION' and obj.instance_collection is not None: + if obj.instance_type == "COLLECTION" and obj.instance_collection is not None: if not obj.visible_get(): continue # Check if this collection contains linked IFC objects coll = obj.instance_collection - is_linked_ifc = any("guids" in child for child in coll.all_objects if child.type == 'MESH') + is_linked_ifc = any("guids" in child for child in coll.all_objects if child.type == "MESH") if is_linked_ifc: print(f"Skipping collection instance '{obj.name}' (linked IFC model, exported via IFC serializer)") continue @@ -200,7 +200,7 @@ class ExportOBJ(bpy.types.Operator): continue eval_obj = dep_inst.object - if eval_obj.type != 'MESH': + if eval_obj.type != "MESH": continue try: @@ -252,7 +252,7 @@ class ExportOBJ(bpy.types.Operator): """ non_ifc_meshes = [] for obj in bpy.data.objects: - if obj.type != 'MESH': + if obj.type != "MESH": continue if not obj.visible_get(): continue @@ -338,7 +338,9 @@ class ExportOBJ(bpy.types.Operator): mtl_file_path = os.path.join(output_dir, "model.mtl") visible_elements = self._get_exportable_elements(ifc_file, filter_visibility=True) - mats = self._export_ifc_to_obj(ifc_file, obj_file_path, mtl_file_path, settings, serializer_settings, visible_elements) + mats = self._export_ifc_to_obj( + ifc_file, obj_file_path, mtl_file_path, settings, serializer_settings, visible_elements + ) ifc_materials.extend(mats) self.report({"INFO"}, f"Exported main model OBJ to: {obj_file_path}") @@ -451,9 +453,15 @@ class CleanupRadianceFiles(bpy.types.Operator): return {"CANCELLED"} cleanup_patterns = ( - "model.obj", "model.mtl", "model.rtm", - "sky.rad", "materials.rad", "scene.rad", - "ascene.oct", "mascene.oct", "ascene.amb", + "model.obj", + "model.mtl", + "model.rtm", + "sky.rad", + "materials.rad", + "scene.rad", + "ascene.oct", + "mascene.oct", + "ascene.amb", ) cleanup_extensions = (".hdr", ".tiff", ".rad", ".dat") cleanup_prefixes = ("instance_", "linked_", "blender_meshes") diff --git a/src/bonsai/bonsai/bim/module/light/ies.py b/src/bonsai/bonsai/bim/module/light/ies.py index 5afd55cd0d..5435caf271 100644 --- a/src/bonsai/bonsai/bim/module/light/ies.py +++ b/src/bonsai/bonsai/bim/module/light/ies.py @@ -78,4 +78,3 @@ class RemoveIESLight(bpy.types.Operator): self.report({"WARNING"}, "Invalid IES light index") return {"CANCELLED"} - diff --git a/src/bonsai/bonsai/bim/module/light/prepare.py b/src/bonsai/bonsai/bim/module/light/prepare.py index 38f53967c8..ea997de578 100644 --- a/src/bonsai/bonsai/bim/module/light/prepare.py +++ b/src/bonsai/bonsai/bim/module/light/prepare.py @@ -254,10 +254,15 @@ class PrepareRadianceScene(bpy.types.Operator): return {"CANCELLED"} sky_data = { - "year": sun_props.year, "month": sun_props.month, "day": sun_props.day, - "hour": sun_props.hour, "minute": sun_props.minute, - "latitude": sun_props.latitude, "longitude": sun_props.longitude, - "UTC_zone": sun_props.UTC_zone, "sun_year": sun_pos_props.year, + "year": sun_props.year, + "month": sun_props.month, + "day": sun_props.day, + "hour": sun_props.hour, + "minute": sun_props.minute, + "latitude": sun_props.latitude, + "longitude": sun_props.longitude, + "UTC_zone": sun_props.UTC_zone, + "sun_year": sun_pos_props.year, "sky_condition": props.sky_condition, "ground_reflectance": props.ground_reflectance, "turbidity": props.turbidity, @@ -286,26 +291,30 @@ class PrepareRadianceScene(bpy.types.Operator): ies_light_data.append(None) continue - ies_light_data.append({ - "ies_file_path": ies_light.ies_file_path, - "lamp_type": ies_light.lamp_type, - "lamp_color": ies_light.lamp_color, - "multiply_factor": ies_light.multiply_factor, - "radius": ies_light.radius, - "rotation_z": ies_light.rotation_z, - "positions": positions, - "is_enabled": ies_light.is_enabled, - }) + ies_light_data.append( + { + "ies_file_path": ies_light.ies_file_path, + "lamp_type": ies_light.lamp_type, + "lamp_color": ies_light.lamp_color, + "multiply_factor": ies_light.multiply_factor, + "radius": ies_light.radius, + "rotation_z": ies_light.rotation_z, + "positions": positions, + "is_enabled": ies_light.is_enabled, + } + ) # Collect material mapping data (must be on main thread) material_mappings = [] for m in props.materials: - material_mappings.append({ - "style_id": m.style_id, - "is_mapped": m.is_mapped, - "category": m.category, - "subcategory": m.subcategory, - }) + material_mappings.append( + { + "style_id": m.style_id, + "is_mapped": m.is_mapped, + "category": m.category, + "subcategory": m.subcategory, + } + ) linked_exports_snapshot = list(linked_model_exports) @@ -315,17 +324,30 @@ class PrepareRadianceScene(bpy.types.Operator): self._error = None import bonsai.bim.module.light.shared as shared + shared.scene = None self._thread = threading.Thread( target=self._prepare_worker, args=( - output_dir, obj_file_path, sky_file_path, - use_hdr, choose_hdr_image, hdr_image_path, hdr_mask_path, sky_map_cal_path, - sky_data, ies_light_data, material_mappings, + output_dir, + obj_file_path, + sky_file_path, + use_hdr, + choose_hdr_image, + hdr_image_path, + hdr_mask_path, + sky_map_cal_path, + sky_data, + ies_light_data, + material_mappings, linked_exports_snapshot, - camera_position, camera_direction, camera_up, - camera_type, camera_fov, camera_ortho_scale, + camera_position, + camera_direction, + camera_up, + camera_type, + camera_fov, + camera_ortho_scale, aspect_ratio, ), daemon=True, @@ -337,41 +359,80 @@ class PrepareRadianceScene(bpy.types.Operator): wm.modal_handler_add(self) self.report({"INFO"}, "Scene preparation started in background...") - context.window.cursor_set('WAIT') + context.window.cursor_set("WAIT") return {"RUNNING_MODAL"} def _prepare_worker( - self, output_dir, obj_file_path, sky_file_path, - use_hdr, choose_hdr_image, hdr_image_path, hdr_mask_path, sky_map_cal_path, - sky_data, ies_light_data, material_mappings, + self, + output_dir, + obj_file_path, + sky_file_path, + use_hdr, + choose_hdr_image, + hdr_image_path, + hdr_mask_path, + sky_map_cal_path, + sky_data, + ies_light_data, + material_mappings, linked_exports_snapshot, - camera_position, camera_direction, camera_up, - camera_type, camera_fov, camera_ortho_scale, + camera_position, + camera_direction, + camera_up, + camera_type, + camera_fov, + camera_ortho_scale, aspect_ratio, ): """Runs in a background thread — no Blender API calls allowed here.""" try: self._do_prepare( - output_dir, obj_file_path, sky_file_path, - use_hdr, choose_hdr_image, hdr_image_path, hdr_mask_path, sky_map_cal_path, - sky_data, ies_light_data, material_mappings, + output_dir, + obj_file_path, + sky_file_path, + use_hdr, + choose_hdr_image, + hdr_image_path, + hdr_mask_path, + sky_map_cal_path, + sky_data, + ies_light_data, + material_mappings, linked_exports_snapshot, - camera_position, camera_direction, camera_up, - camera_type, camera_fov, camera_ortho_scale, + camera_position, + camera_direction, + camera_up, + camera_type, + camera_fov, + camera_ortho_scale, aspect_ratio, ) except Exception as e: self._error = str(e) import traceback + traceback.print_exc() def _do_prepare( - self, output_dir, obj_file_path, sky_file_path, - use_hdr, choose_hdr_image, hdr_image_path, hdr_mask_path, sky_map_cal_path, - sky_data, ies_light_data, material_mappings, + self, + output_dir, + obj_file_path, + sky_file_path, + use_hdr, + choose_hdr_image, + hdr_image_path, + hdr_mask_path, + sky_map_cal_path, + sky_data, + ies_light_data, + material_mappings, linked_exports_snapshot, - camera_position, camera_direction, camera_up, - camera_type, camera_fov, camera_ortho_scale, + camera_position, + camera_direction, + camera_up, + camera_type, + camera_fov, + camera_ortho_scale, aspect_ratio, ): """The actual preparation logic (no Blender API).""" @@ -379,8 +440,7 @@ class PrepareRadianceScene(bpy.types.Operator): # --- Generate sky file --- if sky_data is not None: - dt = datetime(sky_data["year"], sky_data["month"], sky_data["day"], - sky_data["hour"], sky_data["minute"]) + dt = datetime(sky_data["year"], sky_data["month"], sky_data["day"], sky_data["hour"], sky_data["minute"]) print(f"Sun position data for Radiance gensky:") print(f" DateTime: {dt}") @@ -559,8 +619,7 @@ ground_glow source ground file.write("\n# Linked Models\n") for link_idx, (link_rtm_path, link_matrix) in enumerate(linked_rtm_files): is_identity = all( - abs(link_matrix[i][j] - (1.0 if i == j else 0.0)) < 1e-6 - for i in range(4) for j in range(4) + abs(link_matrix[i][j] - (1.0 if i == j else 0.0)) < 1e-6 for i in range(4) for j in range(4) ) if is_identity: @@ -647,7 +706,7 @@ ground_glow source ground print("Scene preparation complete.") def modal(self, context, event): - if event.type == 'TIMER': + if event.type == "TIMER": if self._thread is not None and self._thread.is_alive(): return {"RUNNING_MODAL"} @@ -655,7 +714,7 @@ ground_glow source ground self._cleanup_timer(context) props = tool.Blender.get_radiance_exporter_props() props.is_preparing = False - context.window.cursor_set('DEFAULT') + context.window.cursor_set("DEFAULT") if self._error: self.report({"ERROR"}, f"Scene preparation failed: {self._error}") @@ -666,11 +725,11 @@ ground_glow source ground print(f"Scene preparation completed in {elapsed:.2f} seconds") return {"FINISHED"} - elif event.type == 'ESC': + elif event.type == "ESC": self._cleanup_timer(context) props = tool.Blender.get_radiance_exporter_props() props.is_preparing = False - context.window.cursor_set('DEFAULT') + context.window.cursor_set("DEFAULT") self.report({"WARNING"}, "Scene preparation cannot be cancelled mid-operation") return {"RUNNING_MODAL"} diff --git a/src/bonsai/bonsai/bim/module/light/render.py b/src/bonsai/bonsai/bim/module/light/render.py index cb3d482cf3..1f2a8d76df 100644 --- a/src/bonsai/bonsai/bim/module/light/render.py +++ b/src/bonsai/bonsai/bim/module/light/render.py @@ -91,7 +91,7 @@ class RadianceRender(bpy.types.Operator): wm.modal_handler_add(self) self.report({"INFO"}, "Radiance render started in background...") - context.window.cursor_set('WAIT') + context.window.cursor_set("WAIT") return {"RUNNING_MODAL"} def _render_worker(self, render_scene, output_dir, res_x, res_y, quality, detail, variability, ambient_bounces): @@ -114,14 +114,14 @@ class RadianceRender(bpy.types.Operator): os.chdir(cwd_saved) def modal(self, context, event): - if event.type == 'TIMER': + if event.type == "TIMER": if self._thread is not None and self._thread.is_alive(): return {"RUNNING_MODAL"} self._cleanup_timer(context) props = tool.Blender.get_radiance_exporter_props() props.is_rendering = False - context.window.cursor_set('DEFAULT') + context.window.cursor_set("DEFAULT") if self._error: self.report({"ERROR"}, f"Radiance render failed: {self._error}") @@ -156,11 +156,11 @@ class RadianceRender(bpy.types.Operator): return {"FINISHED"} - elif event.type == 'ESC': + elif event.type == "ESC": self._cleanup_timer(context) props = tool.Blender.get_radiance_exporter_props() props.is_rendering = False - context.window.cursor_set('DEFAULT') + context.window.cursor_set("DEFAULT") self.report({"WARNING"}, "Render cancelled by user. Background process may still be running.") return {"CANCELLED"} @@ -210,9 +210,11 @@ class FalseColorRadiance(bpy.types.Operator): # fc (foot-candles) = 16.629..., lux & cd/m2 = 179.0 multiplier = 179.0 if props.false_color_label in ("lux", "cd/m2") else 16.629505759940542 - print(f"False color parameters: label={props.false_color_label}, scale={fc_scale}, " - f"steps={props.false_color_steps}, multiplier={multiplier}, " - f"contour={props.false_color_contour_lines}") + print( + f"False color parameters: label={props.false_color_label}, scale={fc_scale}, " + f"steps={props.false_color_steps}, multiplier={multiplier}, " + f"contour={props.false_color_contour_lines}" + ) try: fc_output_name = props.false_color_output_name @@ -229,9 +231,12 @@ class FalseColorRadiance(bpy.types.Operator): return {"CANCELLED"} else: import shutil + falsecolor_bin = shutil.which("falsecolor") or shutil.which("falsecolor.exe") if not falsecolor_bin: - self.report({"ERROR"}, "Set the Radiance Bin path in False Color settings, or add Radiance to system PATH.") + self.report( + {"ERROR"}, "Set the Radiance Bin path in False Color settings, or add Radiance to system PATH." + ) return {"CANCELLED"} radiance_bin_dir = os.path.dirname(falsecolor_bin) @@ -299,5 +304,6 @@ class FalseColorRadiance(bpy.types.Operator): except Exception as e: self.report({"ERROR"}, f"Failed to generate false color image: {str(e)}") import traceback + traceback.print_exc() return {"CANCELLED"} diff --git a/src/bonsai/bonsai/bim/module/light/ui.py b/src/bonsai/bonsai/bim/module/light/ui.py index 0649810864..d1bc8b0fad 100644 --- a/src/bonsai/bonsai/bim/module/light/ui.py +++ b/src/bonsai/bonsai/bim/module/light/ui.py @@ -30,6 +30,7 @@ from bonsai.bim.module.light.data import SolarData # Root panel (replaces the old "Radiance Exporter" nested panel) # --------------------------------------------------------------------------- + class BIM_PT_radiance_exporter(bpy.types.Panel): bl_label = "Radiance Exporter" bl_idname = "BIM_PT_radiance_exporter" @@ -47,6 +48,7 @@ class BIM_PT_radiance_exporter(bpy.types.Panel): # 1. Scene Setup # --------------------------------------------------------------------------- + class BIM_PT_radiance_scene_setup(bpy.types.Panel): bl_label = "Scene Setup" bl_idname = "BIM_PT_radiance_scene_setup" @@ -80,6 +82,7 @@ class BIM_PT_radiance_scene_setup(bpy.types.Panel): # 2. Materials # --------------------------------------------------------------------------- + class BIM_PT_radiance_materials(bpy.types.Panel): bl_label = "Materials" bl_idname = "BIM_PT_radiance_materials" @@ -125,6 +128,7 @@ class BIM_PT_radiance_materials(bpy.types.Panel): # 3. Lighting (Environment + IES) # --------------------------------------------------------------------------- + class BIM_PT_radiance_lighting(bpy.types.Panel): bl_label = "Lighting" bl_idname = "BIM_PT_radiance_lighting" @@ -161,10 +165,7 @@ class BIM_PT_radiance_lighting(bpy.types.Panel): col = row.column(align=True) col.operator("radiance.add_ies_light", text="", icon="ADD") - if ( - len(props.ies_lights) > 0 - and 0 <= props.active_ies_light_index < len(props.ies_lights) - ): + if len(props.ies_lights) > 0 and 0 <= props.active_ies_light_index < len(props.ies_lights): active_light = props.ies_lights[props.active_ies_light_index] col = box.column(align=True) @@ -198,6 +199,7 @@ class BIM_PT_radiance_lighting(bpy.types.Panel): # 4. Render Settings # --------------------------------------------------------------------------- + class BIM_PT_radiance_render_settings(bpy.types.Panel): bl_label = "Render Settings" bl_idname = "BIM_PT_radiance_render_settings" @@ -236,6 +238,7 @@ class BIM_PT_radiance_render_settings(bpy.types.Panel): # 5. Pipeline (Steps 1-4 + Cleanup) # --------------------------------------------------------------------------- + class BIM_PT_radiance_pipeline(bpy.types.Panel): bl_label = "Pipeline" bl_idname = "BIM_PT_radiance_pipeline" @@ -318,6 +321,7 @@ class BIM_PT_radiance_pipeline(bpy.types.Panel): # Solar Panel (unchanged) # --------------------------------------------------------------------------- + class BIM_PT_solar(bpy.types.Panel): """Creates a Panel in the render properties window"""