mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-27 18:57:17 +00:00
Add sun path visualisation for solar analysis
This commit is contained in:
@@ -25,6 +25,7 @@ classes = (
|
|||||||
operator.ImportLatLong,
|
operator.ImportLatLong,
|
||||||
operator.ImportTrueNorth,
|
operator.ImportTrueNorth,
|
||||||
operator.RadianceRender,
|
operator.RadianceRender,
|
||||||
|
operator.VisualiseShadows,
|
||||||
prop.BIMSolarProperties,
|
prop.BIMSolarProperties,
|
||||||
prop.RadianceExporterProperties,
|
prop.RadianceExporterProperties,
|
||||||
ui.BIM_PT_radiance_exporter,
|
ui.BIM_PT_radiance_exporter,
|
||||||
|
|||||||
@@ -28,11 +28,12 @@ import blenderbim.tool as tool
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Union
|
from typing import Union
|
||||||
from blenderbim.bim.module.light.data import SolarData
|
from blenderbim.bim.module.light.data import SolarData
|
||||||
|
from blenderbim.bim.module.light.decorator import SolarDecorator
|
||||||
|
|
||||||
|
|
||||||
class ExportOBJ(bpy.types.Operator):
|
class ExportOBJ(bpy.types.Operator):
|
||||||
"""Exports the IFC File to OBJ"""
|
"""Exports the IFC File to OBJ"""
|
||||||
|
|
||||||
bl_idname = "export_scene.radiance"
|
bl_idname = "export_scene.radiance"
|
||||||
bl_label = "Export"
|
bl_label = "Export"
|
||||||
bl_description = "Export the IFC to OBJ"
|
bl_description = "Export the IFC to OBJ"
|
||||||
@@ -43,21 +44,21 @@ class ExportOBJ(bpy.types.Operator):
|
|||||||
quality = context.scene.radiance_exporter_properties.radiance_quality.upper()
|
quality = context.scene.radiance_exporter_properties.radiance_quality.upper()
|
||||||
detail = context.scene.radiance_exporter_properties.radiance_detail.upper()
|
detail = context.scene.radiance_exporter_properties.radiance_detail.upper()
|
||||||
variability = context.scene.radiance_exporter_properties.radiance_variability.upper()
|
variability = context.scene.radiance_exporter_properties.radiance_variability.upper()
|
||||||
|
|
||||||
# Calculate the aspect ratio
|
# Calculate the aspect ratio
|
||||||
aspect_ratio = resolution_x / resolution_y
|
aspect_ratio = resolution_x / resolution_y
|
||||||
|
|
||||||
# Get the blend file path and create the "Radiance Rendering" directory
|
# Get the blend file path and create the "Radiance Rendering" directory
|
||||||
self.report({'INFO'}, "Exporting Radiance files...")
|
self.report({"INFO"}, "Exporting Radiance files...")
|
||||||
blend_file_path = bpy.data.filepath
|
blend_file_path = bpy.data.filepath
|
||||||
if not blend_file_path:
|
if not blend_file_path:
|
||||||
self.report({'ERROR'}, "Please save the Blender file before exporting.")
|
self.report({"ERROR"}, "Please save the Blender file before exporting.")
|
||||||
return {'CANCELLED'}
|
return {"CANCELLED"}
|
||||||
|
|
||||||
blend_file_dir = os.path.dirname(blend_file_path)
|
blend_file_dir = os.path.dirname(blend_file_path)
|
||||||
radiance_dir = os.path.join(blend_file_dir, "RadianceRendering")
|
radiance_dir = os.path.join(blend_file_dir, "RadianceRendering")
|
||||||
|
|
||||||
self.report({'INFO'}, "Radiance directory: {}".format(radiance_dir))
|
self.report({"INFO"}, "Radiance directory: {}".format(radiance_dir))
|
||||||
|
|
||||||
if not os.path.exists(radiance_dir):
|
if not os.path.exists(radiance_dir):
|
||||||
os.makedirs(radiance_dir)
|
os.makedirs(radiance_dir)
|
||||||
@@ -67,7 +68,6 @@ class ExportOBJ(bpy.types.Operator):
|
|||||||
# Settings for obj
|
# Settings for obj
|
||||||
|
|
||||||
serializer_settings = ifcopenshell.geom.serializer_settings()
|
serializer_settings = ifcopenshell.geom.serializer_settings()
|
||||||
|
|
||||||
|
|
||||||
settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.SURFACES_AND_SOLIDS)
|
settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.SURFACES_AND_SOLIDS)
|
||||||
settings.set("apply-default-materials", True)
|
settings.set("apply-default-materials", True)
|
||||||
@@ -76,19 +76,17 @@ class ExportOBJ(bpy.types.Operator):
|
|||||||
|
|
||||||
ifc_file_name = context.scene.radiance_exporter_properties.ifc_file_name
|
ifc_file_name = context.scene.radiance_exporter_properties.ifc_file_name
|
||||||
ifc_file_path = os.path.join(blend_file_dir, f"{ifc_file_name}.ifc")
|
ifc_file_path = os.path.join(blend_file_dir, f"{ifc_file_name}.ifc")
|
||||||
|
|
||||||
if not os.path.exists(ifc_file_path):
|
if not os.path.exists(ifc_file_path):
|
||||||
self.report({'ERROR'}, f"IFC file not found: {ifc_file_path}")
|
self.report({"ERROR"}, f"IFC file not found: {ifc_file_path}")
|
||||||
return {'CANCELLED'}
|
return {"CANCELLED"}
|
||||||
|
|
||||||
|
|
||||||
ifc_file = ifcopenshell.open(ifc_file_path)
|
ifc_file = ifcopenshell.open(ifc_file_path)
|
||||||
for material in ifc_file.by_type("IfcMaterial"):
|
for material in ifc_file.by_type("IfcMaterial"):
|
||||||
self.report({'INFO'}, f"Material: {material.Name}, ID: {material.id()}")
|
self.report({"INFO"}, f"Material: {material.Name}, ID: {material.id()}")
|
||||||
|
|
||||||
obj_file_path = os.path.join(radiance_dir, "model.obj")
|
obj_file_path = os.path.join(radiance_dir, "model.obj")
|
||||||
mtl_file_path = os.path.join(radiance_dir, "model.mtl")
|
mtl_file_path = os.path.join(radiance_dir, "model.mtl")
|
||||||
|
|
||||||
|
|
||||||
# serialiser = ifcopenshell.geom.serializers.obj(obj_file_path, mtl_file_path, settings, ifcopenshell.geom.serializer_settings())
|
# serialiser = ifcopenshell.geom.serializers.obj(obj_file_path, mtl_file_path, settings, ifcopenshell.geom.serializer_settings())
|
||||||
serialiser = ifcopenshell.geom.serializers.obj(obj_file_path, mtl_file_path, settings, serializer_settings)
|
serialiser = ifcopenshell.geom.serializers.obj(obj_file_path, mtl_file_path, settings, serializer_settings)
|
||||||
@@ -104,8 +102,8 @@ class ExportOBJ(bpy.types.Operator):
|
|||||||
break
|
break
|
||||||
serialiser.finalize()
|
serialiser.finalize()
|
||||||
|
|
||||||
return {'FINISHED'}
|
return {"FINISHED"}
|
||||||
|
|
||||||
def getResolution(self, context):
|
def getResolution(self, context):
|
||||||
scene = context.scene
|
scene = context.scene
|
||||||
props = scene.radiance_exporter_properties
|
props = scene.radiance_exporter_properties
|
||||||
@@ -116,31 +114,31 @@ class ExportOBJ(bpy.types.Operator):
|
|||||||
|
|
||||||
class RadianceRender(bpy.types.Operator):
|
class RadianceRender(bpy.types.Operator):
|
||||||
"""Radiance Rendering"""
|
"""Radiance Rendering"""
|
||||||
|
|
||||||
bl_idname = "render_scene.radiance"
|
bl_idname = "render_scene.radiance"
|
||||||
bl_label = "Render"
|
bl_label = "Render"
|
||||||
bl_description = "Renders the scene using Radiance"
|
bl_description = "Renders the scene using Radiance"
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
if pr is None:
|
if pr is None:
|
||||||
self.report({'ERROR'}, "PyRadiance is not available. Cannot perform rendering.")
|
self.report({"ERROR"}, "PyRadiance is not available. Cannot perform rendering.")
|
||||||
return {'CANCELLED'}
|
return {"CANCELLED"}
|
||||||
|
|
||||||
# Get the resolution from the user input
|
# Get the resolution from the user input
|
||||||
resolution_x, resolution_y = self.getResolution(context)
|
resolution_x, resolution_y = self.getResolution(context)
|
||||||
quality = context.scene.radiance_exporter_properties.radiance_quality.upper()
|
quality = context.scene.radiance_exporter_properties.radiance_quality.upper()
|
||||||
detail = context.scene.radiance_exporter_properties.radiance_detail.upper()
|
detail = context.scene.radiance_exporter_properties.radiance_detail.upper()
|
||||||
variability = context.scene.radiance_exporter_properties.radiance_variability.upper()
|
variability = context.scene.radiance_exporter_properties.radiance_variability.upper()
|
||||||
|
|
||||||
# Get the blend file path and create the "Radiance Rendering" directory
|
# Get the blend file path and create the "Radiance Rendering" directory
|
||||||
blend_file_path = bpy.data.filepath
|
blend_file_path = bpy.data.filepath
|
||||||
if not blend_file_path:
|
if not blend_file_path:
|
||||||
self.report({'ERROR'}, "Please save the Blender file before rendering.")
|
self.report({"ERROR"}, "Please save the Blender file before rendering.")
|
||||||
return {'CANCELLED'}
|
return {"CANCELLED"}
|
||||||
|
|
||||||
blend_file_dir = os.path.dirname(blend_file_path)
|
blend_file_dir = os.path.dirname(blend_file_path)
|
||||||
radiance_dir = os.path.join(blend_file_dir, "RadianceRendering")
|
radiance_dir = os.path.join(blend_file_dir, "RadianceRendering")
|
||||||
|
|
||||||
|
|
||||||
# Material processing
|
# Material processing
|
||||||
style = []
|
style = []
|
||||||
obj_file_path = os.path.join(radiance_dir, "model.obj")
|
obj_file_path = os.path.join(radiance_dir, "model.obj")
|
||||||
@@ -153,19 +151,18 @@ class RadianceRender(bpy.types.Operator):
|
|||||||
# json_file_path = os.path.join(blend_file_dir, "material_mapping.json")
|
# json_file_path = os.path.join(blend_file_dir, "material_mapping.json")
|
||||||
|
|
||||||
json_file_path = context.scene.radiance_exporter_properties.json_file_path
|
json_file_path = context.scene.radiance_exporter_properties.json_file_path
|
||||||
self.report({'INFO'}, f"Selected JSON file: {json_file_path}")
|
self.report({"INFO"}, f"Selected JSON file: {json_file_path}")
|
||||||
if json_file_path:
|
if json_file_path:
|
||||||
# self.report({'INFO'}, f"Selected JSON file: {json_file_name}")
|
# self.report({'INFO'}, f"Selected JSON file: {json_file_name}")
|
||||||
json_dest_path = os.path.join(blend_file_dir, json_file_path.split("\\")[-1])
|
json_dest_path = os.path.join(blend_file_dir, json_file_path.split("\\")[-1])
|
||||||
shutil.copy(json_file_path, json_dest_path)
|
shutil.copy(json_file_path, json_dest_path)
|
||||||
self.report({'INFO'}, f"JSON file saved to: {json_dest_path}")
|
self.report({"INFO"}, f"JSON file saved to: {json_dest_path}")
|
||||||
else:
|
else:
|
||||||
self.report({'WARNING'}, "No JSON file selected")
|
self.report({"WARNING"}, "No JSON file selected")
|
||||||
|
|
||||||
|
with open(json_file_path, "r") as file:
|
||||||
with open(json_file_path, 'r') as file:
|
|
||||||
data = json.load(file)
|
data = json.load(file)
|
||||||
|
|
||||||
# Create materials.rad file
|
# Create materials.rad file
|
||||||
materials_file = os.path.join(radiance_dir, "materials.rad")
|
materials_file = os.path.join(radiance_dir, "materials.rad")
|
||||||
with open(materials_file, "w") as file:
|
with open(materials_file, "w") as file:
|
||||||
@@ -180,18 +177,18 @@ class RadianceRender(bpy.types.Operator):
|
|||||||
for i in set(style):
|
for i in set(style):
|
||||||
file.write("inherit alias " + i + " " + data.get(i, "white") + "\n")
|
file.write("inherit alias " + i + " " + data.get(i, "white") + "\n")
|
||||||
|
|
||||||
self.report({'INFO'}, "Exported Materials Rad file to: {}".format(materials_file))
|
self.report({"INFO"}, "Exported Materials Rad file to: {}".format(materials_file))
|
||||||
|
|
||||||
# Run obj2mesh
|
# Run obj2mesh
|
||||||
rtm_file_path = os.path.join(radiance_dir, "model.rtm")
|
rtm_file_path = os.path.join(radiance_dir, "model.rtm")
|
||||||
mesh_file_path = save_obj2mesh_output(obj_file_path, rtm_file_path, matfiles=[materials_file])
|
mesh_file_path = save_obj2mesh_output(obj_file_path, rtm_file_path, matfiles=[materials_file])
|
||||||
# subprocess.run(["obj2mesh", "-a", materials_file, obj_file_path, rtm_file_path])
|
# subprocess.run(["obj2mesh", "-a", materials_file, obj_file_path, rtm_file_path])
|
||||||
self.report({'INFO'}, "obj2mesh output: {}".format(mesh_file_path))
|
self.report({"INFO"}, "obj2mesh output: {}".format(mesh_file_path))
|
||||||
scene_file = os.path.join(radiance_dir, "scene.rad")
|
scene_file = os.path.join(radiance_dir, "scene.rad")
|
||||||
with open(scene_file, "w") as file:
|
with open(scene_file, "w") as file:
|
||||||
file.write("void mesh model\n1 " + rtm_file_path + "\n0\n0\n")
|
file.write("void mesh model\n1 " + rtm_file_path + "\n0\n0\n")
|
||||||
|
|
||||||
self.report({'INFO'}, "Exported Scene file to: {}".format(scene_file))
|
self.report({"INFO"}, "Exported Scene file to: {}".format(scene_file))
|
||||||
|
|
||||||
# Py Radiance Rendering code
|
# Py Radiance Rendering code
|
||||||
scene = pr.Scene("ascene")
|
scene = pr.Scene("ascene")
|
||||||
@@ -207,15 +204,21 @@ class RadianceRender(bpy.types.Operator):
|
|||||||
|
|
||||||
octpath = os.path.join(blend_file_dir, "ascene.oct")
|
octpath = os.path.join(blend_file_dir, "ascene.oct")
|
||||||
print("Reached here")
|
print("Reached here")
|
||||||
image = pr.render(scene, ambbounce=1, resolution=(resolution_x, resolution_y),
|
image = pr.render(
|
||||||
quality=quality, detail=detail, variability=variability)
|
scene,
|
||||||
|
ambbounce=1,
|
||||||
|
resolution=(resolution_x, resolution_y),
|
||||||
|
quality=quality,
|
||||||
|
detail=detail,
|
||||||
|
variability=variability,
|
||||||
|
)
|
||||||
|
|
||||||
raw_hdr_path = os.path.join(radiance_dir, "raw.hdr")
|
raw_hdr_path = os.path.join(radiance_dir, "raw.hdr")
|
||||||
with open(raw_hdr_path, "wb") as wtr:
|
with open(raw_hdr_path, "wb") as wtr:
|
||||||
wtr.write(image)
|
wtr.write(image)
|
||||||
|
|
||||||
self.report({'INFO'}, "Radiance rendering completed. Output: {}".format(raw_hdr_path))
|
self.report({"INFO"}, "Radiance rendering completed. Output: {}".format(raw_hdr_path))
|
||||||
return {'FINISHED'}
|
return {"FINISHED"}
|
||||||
|
|
||||||
def getResolution(self, context):
|
def getResolution(self, context):
|
||||||
scene = context.scene
|
scene = context.scene
|
||||||
@@ -224,10 +227,11 @@ class RadianceRender(bpy.types.Operator):
|
|||||||
resolution_y = props.radiance_resolution_y
|
resolution_y = props.radiance_resolution_y
|
||||||
return resolution_x, resolution_y
|
return resolution_x, resolution_y
|
||||||
|
|
||||||
|
|
||||||
def save_obj2mesh_output(inp: Union[bytes, str, Path], output_file: str, **kwargs):
|
def save_obj2mesh_output(inp: Union[bytes, str, Path], output_file: str, **kwargs):
|
||||||
output_bytes = pr.obj2mesh(inp, **kwargs)
|
output_bytes = pr.obj2mesh(inp, **kwargs)
|
||||||
|
|
||||||
with open(output_file, 'wb') as f:
|
with open(output_file, "wb") as f:
|
||||||
f.write(output_bytes)
|
f.write(output_bytes)
|
||||||
return output_file
|
return output_file
|
||||||
|
|
||||||
@@ -269,3 +273,21 @@ class ImportLatLong(bpy.types.Operator):
|
|||||||
props.latitude = ifcopenshell.util.geolocation.dms2dd(*site.RefLatitude)
|
props.latitude = ifcopenshell.util.geolocation.dms2dd(*site.RefLatitude)
|
||||||
props.longitude = ifcopenshell.util.geolocation.dms2dd(*site.RefLongitude)
|
props.longitude = ifcopenshell.util.geolocation.dms2dd(*site.RefLongitude)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
class VisualiseShadows(bpy.types.Operator):
|
||||||
|
bl_idname = "bim.visualise_shadows"
|
||||||
|
bl_label = "Visualise Shadows"
|
||||||
|
bl_description = "Enables a visual style to display shadows easily"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
context.scene.render.engine = "BLENDER_WORKBENCH"
|
||||||
|
context.scene.display.shading.light = "FLAT"
|
||||||
|
context.scene.display.shading.show_shadows = True
|
||||||
|
context.scene.display.shadow_focus = 1.0
|
||||||
|
context.scene.view_settings.view_transform = "Standard" # Preserve shading colours
|
||||||
|
space = tool.Blender.get_view3d_space()
|
||||||
|
space.shading.type = "RENDERED"
|
||||||
|
SolarDecorator.install(bpy.context)
|
||||||
|
return {"FINISHED"}
|
||||||
|
|||||||
@@ -20,8 +20,10 @@ import bpy
|
|||||||
import pytz
|
import pytz
|
||||||
import tzfpy
|
import tzfpy
|
||||||
import datetime
|
import datetime
|
||||||
from math import radians
|
import sun_position.sun_calc
|
||||||
from bpy.props import IntProperty, StringProperty, EnumProperty, FloatProperty
|
from math import radians, pi
|
||||||
|
from mathutils import Euler, Vector, Matrix
|
||||||
|
from bpy.props import IntProperty, StringProperty, EnumProperty, FloatProperty, FloatVectorProperty
|
||||||
from bpy.types import PropertyGroup
|
from bpy.types import PropertyGroup
|
||||||
from blenderbim.bim.module.light.data import SolarData
|
from blenderbim.bim.module.light.data import SolarData
|
||||||
|
|
||||||
@@ -46,6 +48,9 @@ def update_hourminute(self, context):
|
|||||||
|
|
||||||
|
|
||||||
def update_date(self, context):
|
def update_date(self, context):
|
||||||
|
sun_props = context.scene.sun_pos_properties
|
||||||
|
sun_props.month = self.month
|
||||||
|
sun_props.day = self.day
|
||||||
update_sun_path()
|
update_sun_path()
|
||||||
|
|
||||||
|
|
||||||
@@ -53,16 +58,48 @@ def update_true_north(self, context):
|
|||||||
sun_props = context.scene.sun_pos_properties
|
sun_props = context.scene.sun_pos_properties
|
||||||
# Preserve IFC sign convention
|
# Preserve IFC sign convention
|
||||||
sun_props.north_offset = radians(self.true_north * -1)
|
sun_props.north_offset = radians(self.true_north * -1)
|
||||||
|
update_sun_path()
|
||||||
|
|
||||||
|
|
||||||
|
def update_sun_path_size(self, context):
|
||||||
|
sun_props = context.scene.sun_pos_properties
|
||||||
|
sun_props.sun_distance = self.sun_path_size
|
||||||
|
update_sun_path()
|
||||||
|
|
||||||
|
|
||||||
def update_sun_path():
|
def update_sun_path():
|
||||||
props = bpy.context.scene.BIMSolarProperties
|
props = bpy.context.scene.BIMSolarProperties
|
||||||
sun_props = bpy.context.scene.sun_pos_properties
|
sun_props = bpy.context.scene.sun_pos_properties
|
||||||
timezone = pytz.timezone(tzfpy.get_tz(props.longitude, props.latitude))
|
timezone = pytz.timezone(tzfpy.get_tz(props.longitude, props.latitude))
|
||||||
dt = datetime.datetime(datetime.datetime.now(datetime.UTC).year, int(props.month), props.date, props.hour, props.minute)
|
dt = datetime.datetime(sun_props.year, sun_props.month, sun_props.day, props.hour, props.minute)
|
||||||
local_time = timezone.localize(dt, is_dst=None)
|
local_time = timezone.localize(dt, is_dst=None)
|
||||||
sun_props.use_daylight_savings = bool(local_time.dst())
|
sun_props.use_daylight_savings = bool(local_time.dst())
|
||||||
sun_props.UTC_zone = local_time.utcoffset().total_seconds() / 3600
|
sun_props.UTC_zone = local_time.utcoffset().total_seconds() / 3600
|
||||||
|
zone = -sun_props.UTC_zone
|
||||||
|
if sun_props.use_daylight_savings:
|
||||||
|
zone -= 1
|
||||||
|
azimuth, elevation = sun_position.sun_calc.get_sun_coordinates(
|
||||||
|
sun_props.time,
|
||||||
|
sun_props.latitude,
|
||||||
|
sun_props.longitude,
|
||||||
|
zone,
|
||||||
|
sun_props.month,
|
||||||
|
sun_props.day,
|
||||||
|
sun_props.year,
|
||||||
|
)
|
||||||
|
sun_vector = sun_position.sun_calc.get_sun_vector(azimuth, elevation) * sun_props.sun_distance
|
||||||
|
props.sun_position = sun_vector
|
||||||
|
# sun_vector.z = max(0, sun_vector.z)
|
||||||
|
# Light direction is a bit weird?
|
||||||
|
mat = Matrix(((-1.0, 0.0, 0.0, 0.0), (0.0, 0, 1.0, 0.0), (-0.0, -1.0, 0, 0.0), (0.0, 0.0, 0.0, 1.0))).inverted()
|
||||||
|
if sun_vector.z < 0:
|
||||||
|
bpy.context.scene.display.light_direction = mat @ Vector((0, 0, 1))
|
||||||
|
else:
|
||||||
|
rotation_euler = Euler((elevation - pi / 2, 0, -azimuth))
|
||||||
|
bpy.context.scene.display.light_direction = mat @ (
|
||||||
|
rotation_euler.to_quaternion() @ Vector((0, 0, -1))
|
||||||
|
)
|
||||||
|
SolarData.data["sun"] = sun_vector
|
||||||
|
|
||||||
|
|
||||||
class RadianceExporterProperties(PropertyGroup):
|
class RadianceExporterProperties(PropertyGroup):
|
||||||
@@ -118,29 +155,10 @@ class BIMSolarProperties(PropertyGroup):
|
|||||||
latitude: FloatProperty(name="Latitude", min=-90, max=90, update=update_latlong)
|
latitude: FloatProperty(name="Latitude", min=-90, max=90, update=update_latlong)
|
||||||
longitude: FloatProperty(name="Longitude", min=-180, max=180, update=update_latlong)
|
longitude: FloatProperty(name="Longitude", min=-180, max=180, update=update_latlong)
|
||||||
true_north: FloatProperty(name="True North", min=-180, max=180, update=update_true_north)
|
true_north: FloatProperty(name="True North", min=-180, max=180, update=update_true_north)
|
||||||
month: EnumProperty(
|
month: IntProperty(name="Month", min=1, max=12, default=1, update=update_date)
|
||||||
name="Month",
|
day: IntProperty(name="Date", min=1, max=31, default=1, update=update_date)
|
||||||
items=[
|
|
||||||
(str(i + 1), m, "")
|
|
||||||
for i, m in enumerate(
|
|
||||||
(
|
|
||||||
"January",
|
|
||||||
"February",
|
|
||||||
"March",
|
|
||||||
"April",
|
|
||||||
"May",
|
|
||||||
"June",
|
|
||||||
"July",
|
|
||||||
"August",
|
|
||||||
"September",
|
|
||||||
"October",
|
|
||||||
"November",
|
|
||||||
"December",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
],
|
|
||||||
update=update_date
|
|
||||||
)
|
|
||||||
date: IntProperty(name="Date", min=1, max=31, default=1, update=update_date)
|
|
||||||
hour: IntProperty(name="Hour", min=0, max=23, update=update_hourminute)
|
hour: IntProperty(name="Hour", min=0, max=23, update=update_hourminute)
|
||||||
minute: IntProperty(name="Minute", min=0, max=59, update=update_hourminute)
|
minute: IntProperty(name="Minute", min=0, max=59, update=update_hourminute)
|
||||||
|
sun_position: FloatVectorProperty(name="Sun Position", subtype="XYZ", default=(0, 0, 0))
|
||||||
|
sun_path_origin: FloatVectorProperty(name="Sun Path Origin", subtype="XYZ", default=(10, 0, 0))
|
||||||
|
sun_path_size: FloatProperty(name="Sun Path Size", min=0.1, default=50, update=update_sun_path_size)
|
||||||
|
|||||||
@@ -105,8 +105,21 @@ class BIM_PT_solar(bpy.types.Panel):
|
|||||||
row.operator("bim.import_true_north", icon="IMPORT", text="")
|
row.operator("bim.import_true_north", icon="IMPORT", text="")
|
||||||
|
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.prop(props, "month", text="")
|
row.prop(props, "month", text={
|
||||||
row.prop(props, "date")
|
1: "January",
|
||||||
|
2: "February",
|
||||||
|
3: "March",
|
||||||
|
4: "April",
|
||||||
|
5: "May",
|
||||||
|
6: "June",
|
||||||
|
7: "July",
|
||||||
|
8: "August",
|
||||||
|
9: "September",
|
||||||
|
10: "October",
|
||||||
|
11: "November",
|
||||||
|
12: "December",
|
||||||
|
}[props.month])
|
||||||
|
row.prop(props, "day")
|
||||||
|
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.prop(props, "hour")
|
row.prop(props, "hour")
|
||||||
@@ -134,5 +147,10 @@ class BIM_PT_solar(bpy.types.Panel):
|
|||||||
row2.label(text=f"Sunset: {sunset}")
|
row2.label(text=f"Sunset: {sunset}")
|
||||||
|
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.prop(sun_props, "sun_distance", text="Sun Path Size")
|
row.prop(props, "sun_path_size")
|
||||||
row.prop(sun_props, "show_analemmas", icon="HIDE_ON" if sun_props.show_analemmas else "HIDE_OFF", text="")
|
|
||||||
|
row = self.layout.row()
|
||||||
|
row.prop(context.scene.display.shading, "shadow_intensity", text="Shadow Intensity")
|
||||||
|
|
||||||
|
row = self.layout.row()
|
||||||
|
row.operator("bim.visualise_shadows", text="Visualise Shadows")
|
||||||
|
|||||||
@@ -246,6 +246,13 @@ class Blender(blenderbim.core.tool.Blender):
|
|||||||
if area.type == "VIEW_3D":
|
if area.type == "VIEW_3D":
|
||||||
return area
|
return area
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_view3d_space(cls):
|
||||||
|
if area := cls.get_view3d_area():
|
||||||
|
for space in area.spaces:
|
||||||
|
if space.type == "VIEW_3D":
|
||||||
|
return space
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_blender_prop_default_value(cls, props, prop_name: str) -> Any:
|
def get_blender_prop_default_value(cls, props, prop_name: str) -> Any:
|
||||||
prop_bl_rna = props.bl_rna.properties[prop_name]
|
prop_bl_rna = props.bl_rna.properties[prop_name]
|
||||||
|
|||||||
Reference in New Issue
Block a user