Files
IfcOpenShell/src/bonsai/bonsai/bim/module/light/ui.py
T
2025-11-07 19:13:44 +05:00

253 lines
8.8 KiB
Python

# Bonsai - OpenBIM Blender Add-on
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
#
# This file is part of Bonsai.
#
# Bonsai is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Bonsai is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import calendar
import bpy
import bonsai.tool as tool
from typing import TYPE_CHECKING
from bonsai.bim.module.light.data import SolarData
class BIM_PT_radiance_exporter(bpy.types.Panel):
"""Creates a Panel in the render properties window"""
bl_label = "Radiance Exporter"
bl_idname = "BIM_PT_radiance_exporter"
bl_options = {"DEFAULT_CLOSED"}
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_parent_id = "BIM_PT_tab_lighting"
def draw(self, context):
assert self.layout
layout = self.layout
props = tool.Blender.get_radiance_exporter_props()
if tool.Ifc.get():
row = self.layout.row()
row.prop(props, "should_load_from_memory")
if not tool.Ifc.get() or not props.should_load_from_memory:
row = self.layout.row(align=True)
row.prop(props, "ifc_file")
row = layout.row()
row.prop(props, "output_dir")
row = layout.row()
layout.label(text="Info: Unmapped materials default to white")
row = layout.row()
row.template_list("MATERIAL_UL_radiance_materials", "", props, "materials", props, "active_material_index")
row.operator("radiance.open_spectraldb", text="", icon="WORLD") # Globe icon
if len(props.materials) > 0:
col = layout.column(align=True)
col.prop(props, "category")
if props.category:
col.prop(props, "subcategory")
if props.active_material_index >= 0 and props.active_material_index < len(props.materials):
active_material = props.materials[props.active_material_index]
if active_material.category and active_material.subcategory:
layout.label(
text=f"Mapped: {active_material.name} to {active_material.category} - {active_material.subcategory}"
)
else:
layout.label(text=f"Select category and subcategory for: {active_material.name}")
row = layout.row()
row.operator("radiance.import_material_mappings", text="Import Mappings", icon="IMPORT")
row.operator("radiance.export_material_mappings", text="Export Mappings", icon="EXPORT")
row = layout.row()
row.operator("bim.refresh_ifc_materials", text="Refresh IFC Materials")
layout.separator()
row = layout.row()
layout.label(text="Step 1: Export geometry for simulation")
row = layout.row()
row.operator("export_scene.radiance", text="Export Geometry for Simulation")
layout.separator()
box = layout.box()
box.label(text="Camera Settings")
row = box.row()
row.prop(props, "use_active_camera")
if not props.use_active_camera:
row = box.row()
row.prop(props, "selected_camera")
row.operator("radiance.select_camera", text="", icon="EYEDROPPER")
row = box.row(align=True)
row.label(text="Resolution")
row.prop(props, "radiance_resolution_x", text="X")
row.prop(props, "radiance_resolution_y", text="Y")
row = layout.row()
row.prop(props, "radiance_quality")
row = layout.row()
row.prop(props, "radiance_detail")
row = layout.row()
row.prop(props, "radiance_variability")
layout.separator()
row = layout.row()
row.prop(props, "output_file_name")
row = layout.row()
row.prop(props, "output_file_format")
layout.separator()
row = layout.row()
row.prop(props, "use_hdr")
if props.use_hdr:
row = layout.row()
row.prop(props, "choose_hdr_image")
row = layout.row()
layout.label(text="Step 2: Run the simulation")
row = layout.row()
row.operator("render_scene.radiance", text="Radiance Render")
row.enabled = not props.is_exporting
class BIM_PT_solar(bpy.types.Panel):
"""Creates a Panel in the render properties window"""
bl_label = "Solar Access / Shadow"
bl_idname = "BIM_PT_solar"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_parent_id = "BIM_PT_tab_solar_analysis"
bl_options = {"HIDE_HEADER"}
def draw(self, context):
if not SolarData.is_loaded:
SolarData.load()
assert self.layout
# Props are more reliable as they'll come and go regardless of Data update.
if (sun_props := tool.Blender.get_sun_props()) is None:
self.layout.label(text="Enable 'Sun Position' Add-on To Continue", icon="ERROR")
return
sun_position = SolarData.data["sun_position"]
if sun_position is None:
# There are props, so there must be an addon.
SolarData.data["sun_position"] = SolarData.sun_position()
if TYPE_CHECKING:
import sun_position
props = tool.Blender.get_solar_props()
if SolarData.data["sites"]:
row = self.layout.row(align=True)
row.prop(props, "sites")
row.operator("bim.import_lat_long", icon="IMPORT", text="")
else:
row = self.layout.row(align=True)
row.label(text="No Sites With Lat/Longs Found", icon="ERROR")
row = self.layout.row(align=True)
row.alignment = "RIGHT"
row.operator("bim.light_pick_coordinates", icon="URL", text="Pick")
row = self.layout.row(align=True)
row.prop(props, "coordinates", icon="URL")
row = self.layout.row(align=True)
row.prop(props, "latitude")
row.prop(props, "longitude")
row = self.layout.row(align=True)
row.prop(props, "true_north")
if SolarData.data["true_north"] is not None:
row.operator("bim.import_true_north", icon="IMPORT", text="")
row = self.layout.row()
row.alignment = "RIGHT"
row.operator("bim.light_set_time_to_now", icon="TIME", text="Now")
row = self.layout.row()
row.prop(props, "year")
row = self.layout.row(align=True)
row.prop(props, "month", text=calendar.month_name[props.month])
row.prop(props, "day")
row = self.layout.row(align=True)
row.prop(props, "hour")
row.prop(props, "minute")
col = self.layout.column(align=True)
box = col.box()
row = box.row()
row.alignment = "CENTER"
row.label(text=props.timezone)
row = col.row(align=True)
box = row.box()
local_time = sun_position.sun_calc.format_time(sun_props.time, sun_props.use_daylight_savings)
utc_time = sun_position.sun_calc.format_time(sun_props.time, sun_props.use_daylight_savings, sun_props.UTC_zone)
row2 = box.row()
row2.label(text=f"Local Time: {local_time}")
row2 = box.row()
row2.label(text=f"UTC Time: {utc_time}")
box = row.box()
sunrise = sun_position.sun_calc.format_hms(sun_props.sunrise_time)
sunset = sun_position.sun_calc.format_hms(sun_props.sunset_time)
row2 = box.row()
row2.label(text=f"Sunrise: {sunrise}")
row2 = box.row()
row2.label(text=f"Sunset: {sunset}")
col = self.layout.column(align=True)
row = col.row(align=True)
row.prop(props, "display_sun_path", icon="LIGHT_SUN")
row.prop(props, "sun_path_size")
if props.display_sun_path:
row = col.row()
row.operator("bim.move_sun_path_to_3d_cursor")
row = self.layout.row(align=True)
row.prop(props, "shadow_mode", icon="SHADING_RENDERED", expand=True)
if props.shadow_mode == "SHADING":
row = self.layout.row()
row.prop(context.scene.display.shading, "shadow_intensity", text="Shadow Intensity")
elif props.shadow_mode == "RENDERING":
row = self.layout.row()
sun_props = tool.Blender.get_sun_props()
assert sun_props
row.prop(sun_props.sun_object.data, "energy", text="Sun Intensity")
row = self.layout.row(align=True)
row.operator("bim.view_from_sun", icon="LIGHT_HEMI")