mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 09:21:46 +00:00
typing
This commit is contained in:
@@ -38,18 +38,17 @@ def depsgraph_update_pre_handler(scene):
|
|||||||
|
|
||||||
def set_active_camera_resolution(scene: bpy.types.Scene) -> None:
|
def set_active_camera_resolution(scene: bpy.types.Scene) -> None:
|
||||||
props = tool.Drawing.get_document_props()
|
props = tool.Drawing.get_document_props()
|
||||||
if not scene.camera or "/" not in scene.camera.name or not props.drawings:
|
camera_obj = scene.camera
|
||||||
|
if not camera_obj or "/" not in camera_obj.name or not props.drawings:
|
||||||
return
|
return
|
||||||
assert isinstance(scene.camera.data, bpy.types.Camera)
|
assert isinstance((camera := camera_obj.data), bpy.types.Camera)
|
||||||
props = scene.camera.data.BIMCameraProperties
|
props = tool.Drawing.get_camera_props(camera)
|
||||||
ortho_scale = max((props.width, props.height))
|
ortho_scale = max((props.width, props.height))
|
||||||
aspect_ratio = props.width / props.height
|
aspect_ratio = props.width / props.height
|
||||||
if (scene.camera.data.ortho_scale != ortho_scale) or (
|
if (camera.ortho_scale != ortho_scale) or (scene.render.resolution_x / scene.render.resolution_y != aspect_ratio):
|
||||||
scene.render.resolution_x / scene.render.resolution_y != aspect_ratio
|
camera.ortho_scale = ortho_scale
|
||||||
):
|
|
||||||
scene.camera.data.ortho_scale = ortho_scale
|
|
||||||
|
|
||||||
diagram_scale = tool.Drawing.get_diagram_scale(scene.camera)
|
diagram_scale = tool.Drawing.get_diagram_scale(camera_obj)
|
||||||
scale_ratio = tool.Drawing.get_scale_ratio(diagram_scale["Scale"])
|
scale_ratio = tool.Drawing.get_scale_ratio(diagram_scale["Scale"])
|
||||||
|
|
||||||
if props.width > props.height:
|
if props.width > props.height:
|
||||||
@@ -61,5 +60,5 @@ def set_active_camera_resolution(scene: bpy.types.Scene) -> None:
|
|||||||
raster_x = ortho_scale * aspect_ratio * scale_ratio * props.dpi / 0.0254
|
raster_x = ortho_scale * aspect_ratio * scale_ratio * props.dpi / 0.0254
|
||||||
raster_y = ortho_scale * scale_ratio * props.dpi / 0.0254
|
raster_y = ortho_scale * scale_ratio * props.dpi / 0.0254
|
||||||
|
|
||||||
scene.render.resolution_x = scene.camera.data.BIMCameraProperties.raster_x = int(raster_x)
|
scene.render.resolution_x = props.raster_x = int(raster_x)
|
||||||
scene.render.resolution_y = scene.camera.data.BIMCameraProperties.raster_y = int(raster_y)
|
scene.render.resolution_y = props.raster_y = int(raster_y)
|
||||||
|
|||||||
@@ -413,12 +413,13 @@ def get_project_collection(scene):
|
|||||||
return colls[0]
|
return colls[0]
|
||||||
|
|
||||||
|
|
||||||
def parse_diagram_scale(camera):
|
def parse_diagram_scale(camera: bpy.types.Camera) -> float:
|
||||||
"""Returns numeric value of scale"""
|
"""Returns numeric value of scale"""
|
||||||
if camera.BIMCameraProperties.diagram_scale == "CUSTOM":
|
props = tool.Drawing.get_camera_props(camera)
|
||||||
_, fraction = camera.BIMCameraProperties.custom_diagram_scale.split("|")
|
if props.diagram_scale == "CUSTOM":
|
||||||
|
_, fraction = props.custom_diagram_scale.split("|")
|
||||||
else:
|
else:
|
||||||
_, fraction = camera.BIMCameraProperties.diagram_scale.split("|")
|
_, fraction = props.diagram_scale.split("|")
|
||||||
numerator, denominator = fraction.split("/")
|
numerator, denominator = fraction.split("/")
|
||||||
return float(numerator) / float(denominator)
|
return float(numerator) / float(denominator)
|
||||||
|
|
||||||
@@ -431,12 +432,11 @@ def ortho_view_frame(
|
|||||||
Similar to `bpy.types.Camera.view_frame`
|
Similar to `bpy.types.Camera.view_frame`
|
||||||
|
|
||||||
:arg camera: camera of drawing
|
:arg camera: camera of drawing
|
||||||
:type camera: bpy.types.Camera + BIMCameraProperties
|
|
||||||
:arg margin: margins, in scene units
|
:arg margin: margins, in scene units
|
||||||
:type margin: float
|
|
||||||
:return: (xmin, xmax, ymin, ymax, zmin, zmax) in local camera coordinates
|
:return: (xmin, xmax, ymin, ymax, zmin, zmax) in local camera coordinates
|
||||||
"""
|
"""
|
||||||
aspect = camera.BIMCameraProperties.raster_y / camera.BIMCameraProperties.raster_x
|
props = tool.Drawing.get_camera_props(camera)
|
||||||
|
aspect = props.raster_y / props.raster_x
|
||||||
size = camera.ortho_scale
|
size = camera.ortho_scale
|
||||||
hwidth = size * 0.5
|
hwidth = size * 0.5
|
||||||
hheight = size * 0.5 * aspect
|
hheight = size * 0.5 * aspect
|
||||||
|
|||||||
@@ -228,7 +228,9 @@ class CreateDrawing(bpy.types.Operator):
|
|||||||
if not tool.Drawing.is_drawing_active():
|
if not tool.Drawing.is_drawing_active():
|
||||||
cls.poll_message_set("No active drawing.")
|
cls.poll_message_set("No active drawing.")
|
||||||
return False
|
return False
|
||||||
if context.scene.camera.data.BIMCameraProperties.linework_mode == "FREESTYLE" and not hasattr(
|
assert context.scene
|
||||||
|
assert (camera_obj := context.scene.camera)
|
||||||
|
if tool.Drawing.get_camera_props(camera_obj).linework_mode == "FREESTYLE" and not hasattr(
|
||||||
context.scene, "svg_export"
|
context.scene, "svg_export"
|
||||||
):
|
):
|
||||||
cls.poll_message_set(
|
cls.poll_message_set(
|
||||||
@@ -248,6 +250,7 @@ class CreateDrawing(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
self.props = tool.Drawing.get_document_props()
|
self.props = tool.Drawing.get_document_props()
|
||||||
|
assert context.scene and context.scene.camera
|
||||||
|
|
||||||
active_drawing_id = tool.Blender.get_ifc_definition_id(context.scene.camera)
|
active_drawing_id = tool.Blender.get_ifc_definition_id(context.scene.camera)
|
||||||
if self.print_all:
|
if self.print_all:
|
||||||
@@ -262,13 +265,14 @@ class CreateDrawing(bpy.types.Operator):
|
|||||||
bpy.ops.bim.activate_drawing(drawing=drawing_id, should_view_from_camera=False)
|
bpy.ops.bim.activate_drawing(drawing=drawing_id, should_view_from_camera=False)
|
||||||
|
|
||||||
self.camera = context.scene.camera
|
self.camera = context.scene.camera
|
||||||
self.camera_element = tool.Ifc.get_entity(self.camera)
|
assert (camera_element := tool.Ifc.get_entity(self.camera))
|
||||||
|
self.camera_element = camera_element
|
||||||
self.camera_document = tool.Drawing.get_drawing_document(self.camera_element)
|
self.camera_document = tool.Drawing.get_drawing_document(self.camera_element)
|
||||||
self.file = tool.Ifc.get()
|
self.file = tool.Ifc.get()
|
||||||
|
|
||||||
with profile("Drawing generation process"):
|
with profile("Drawing generation process"):
|
||||||
with profile("Initialize drawing generation process"):
|
with profile("Initialize drawing generation process"):
|
||||||
self.cprops = self.camera.data.BIMCameraProperties
|
self.cprops = tool.Drawing.get_camera_props(self.camera)
|
||||||
self.drawing = self.file.by_id(drawing_id)
|
self.drawing = self.file.by_id(drawing_id)
|
||||||
self.drawing_name = self.drawing.Name
|
self.drawing_name = self.drawing.Name
|
||||||
self.metadata = tool.Drawing.get_drawing_metadata(self.camera_element)
|
self.metadata = tool.Drawing.get_drawing_metadata(self.camera_element)
|
||||||
@@ -297,11 +301,11 @@ class CreateDrawing(bpy.types.Operator):
|
|||||||
|
|
||||||
with profile("Generate linework"):
|
with profile("Generate linework"):
|
||||||
if tool.Drawing.is_camera_orthographic():
|
if tool.Drawing.is_camera_orthographic():
|
||||||
if self.camera.data.BIMCameraProperties.linework_mode == "OPENCASCADE":
|
if self.cprops.linework_mode == "OPENCASCADE":
|
||||||
linework_svg = self.generate_linework(context)
|
linework_svg = self.generate_linework(context)
|
||||||
elif self.camera.data.BIMCameraProperties.linework_mode == "FREESTYLE":
|
elif self.cprops.linework_mode == "FREESTYLE":
|
||||||
linework_svg = self.generate_freestyle_linework(context)
|
linework_svg = self.generate_freestyle_linework(context)
|
||||||
elif self.camera.data.BIMCameraProperties.linework_mode == "FREESTYLE":
|
elif self.cprops.linework_mode == "FREESTYLE":
|
||||||
linework_svg = self.generate_freestyle_linework(context)
|
linework_svg = self.generate_freestyle_linework(context)
|
||||||
|
|
||||||
with profile("Generate annotation"):
|
with profile("Generate annotation"):
|
||||||
@@ -876,19 +880,19 @@ class CreateDrawing(bpy.types.Operator):
|
|||||||
|
|
||||||
return svg_path
|
return svg_path
|
||||||
|
|
||||||
if self.camera.data.BIMCameraProperties.cut_mode == "BISECT":
|
if self.cprops.cut_mode == "BISECT":
|
||||||
self.remove_cut_linework(root)
|
self.remove_cut_linework(root)
|
||||||
self.generate_bisect_linework(context, root)
|
self.generate_bisect_linework(context, root)
|
||||||
self.generate_wall_layers(context, root)
|
self.generate_wall_layers(context, root)
|
||||||
self.merge_linework_and_add_metadata(root)
|
self.merge_linework_and_add_metadata(root)
|
||||||
self.move_elements_to_top(root)
|
self.move_elements_to_top(root)
|
||||||
elif self.camera.data.BIMCameraProperties.cut_mode == "OPENCASCADE":
|
elif self.cprops.cut_mode == "OPENCASCADE":
|
||||||
self.move_projection_to_bottom(root)
|
self.move_projection_to_bottom(root)
|
||||||
self.generate_wall_layers(context, root)
|
self.generate_wall_layers(context, root)
|
||||||
self.merge_linework_and_add_metadata(root)
|
self.merge_linework_and_add_metadata(root)
|
||||||
self.move_elements_to_top(root)
|
self.move_elements_to_top(root)
|
||||||
|
|
||||||
if self.camera.data.BIMCameraProperties.fill_mode == "SHAPELY":
|
if self.cprops.fill_mode == "SHAPELY":
|
||||||
# shapely variant
|
# shapely variant
|
||||||
group = root.find("{http://www.w3.org/2000/svg}g")
|
group = root.find("{http://www.w3.org/2000/svg}g")
|
||||||
|
|
||||||
@@ -960,7 +964,7 @@ class CreateDrawing(bpy.types.Operator):
|
|||||||
path.set("class", " ".join(list(classes)))
|
path.set("class", " ".join(list(classes)))
|
||||||
group.insert(0, path)
|
group.insert(0, path)
|
||||||
|
|
||||||
if self.camera.data.BIMCameraProperties.fill_mode == "SVGFILL":
|
if self.cprops.fill_mode == "SVGFILL":
|
||||||
results = etree.tostring(root).decode("utf8")
|
results = etree.tostring(root).decode("utf8")
|
||||||
svg_data_1 = results
|
svg_data_1 = results
|
||||||
from xml.dom.minidom import parseString
|
from xml.dom.minidom import parseString
|
||||||
@@ -1449,10 +1453,9 @@ class CreateDrawing(bpy.types.Operator):
|
|||||||
g.set("class", " ".join(list(classes)))
|
g.set("class", " ".join(list(classes)))
|
||||||
group.append(g)
|
group.append(g)
|
||||||
|
|
||||||
def drawing_to_model_co(self, x, y):
|
def drawing_to_model_co(self, x: float, y: float) -> Vector:
|
||||||
camera_xy = np.array((x, -y)) / self.scale / 1000
|
camera_xy = np.array((x, -y)) / self.scale / 1000
|
||||||
camera_props = self.camera.data.BIMCameraProperties
|
camera_xy += np.array((self.cprops.width / -2, self.cprops.height / 2)) # top left offset
|
||||||
camera_xy += np.array((camera_props.width / -2, camera_props.height / 2)) # top left offset
|
|
||||||
return self.camera.matrix_world @ Vector(camera_xy).to_3d()
|
return self.camera.matrix_world @ Vector(camera_xy).to_3d()
|
||||||
|
|
||||||
def pythonize(self, arr):
|
def pythonize(self, arr):
|
||||||
@@ -2158,7 +2161,7 @@ class ActivateDrawingBase:
|
|||||||
|
|
||||||
# Save drawing bounds to the .ifc file
|
# Save drawing bounds to the .ifc file
|
||||||
camera = context.scene.camera
|
camera = context.scene.camera
|
||||||
camera_props = camera.data.BIMCameraProperties
|
camera_props = tool.Drawing.get_camera_props(camera)
|
||||||
if camera_props.update_representation(camera):
|
if camera_props.update_representation(camera):
|
||||||
bpy.ops.bim.update_representation(obj=camera.name, ifc_representation_class="")
|
bpy.ops.bim.update_representation(obj=camera.name, ifc_representation_class="")
|
||||||
# See 6452 and 6478.
|
# See 6452 and 6478.
|
||||||
@@ -2298,7 +2301,8 @@ class ReloadDrawingStyles(bpy.types.Operator):
|
|||||||
if not DrawingsData.is_loaded:
|
if not DrawingsData.is_loaded:
|
||||||
DrawingsData.load()
|
DrawingsData.load()
|
||||||
drawing_pset_data = DrawingsData.data["active_drawing_pset_data"]
|
drawing_pset_data = DrawingsData.data["active_drawing_pset_data"]
|
||||||
camera_props = context.scene.camera.data.BIMCameraProperties
|
assert context.scene and (camera := context.scene.camera)
|
||||||
|
camera_props = tool.Drawing.get_camera_props(camera)
|
||||||
|
|
||||||
# added this part as a temporary fallback
|
# added this part as a temporary fallback
|
||||||
# TODO: should remove it a bit later when projects get more accommodated
|
# TODO: should remove it a bit later when projects get more accommodated
|
||||||
@@ -2365,12 +2369,14 @@ class AddDrawingStyle(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
|
assert context.scene and (camera_obj := context.scene.camera)
|
||||||
props = tool.Drawing.get_document_props()
|
props = tool.Drawing.get_document_props()
|
||||||
drawing_styles = props.drawing_styles
|
drawing_styles = props.drawing_styles
|
||||||
new = drawing_styles.add()
|
new = drawing_styles.add()
|
||||||
# drawing style is saved to ifc on rename
|
# drawing style is saved to ifc on rename
|
||||||
new.name = tool.Blender.ensure_unique_name("New Drawing Style", drawing_styles)
|
new.name = tool.Blender.ensure_unique_name("New Drawing Style", drawing_styles)
|
||||||
context.scene.camera.data.BIMCameraProperties.active_drawing_style_index = len(drawing_styles) - 1
|
camera_props = tool.Drawing.get_camera_props(camera_obj)
|
||||||
|
camera_props.active_drawing_style_index = len(drawing_styles) - 1
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@@ -2381,9 +2387,11 @@ class RemoveDrawingStyle(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
index: bpy.props.IntProperty()
|
index: bpy.props.IntProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
|
assert context.scene and (camera_obj := context.scene.camera)
|
||||||
props = tool.Drawing.get_document_props()
|
props = tool.Drawing.get_document_props()
|
||||||
props.drawing_styles.remove(self.index)
|
props.drawing_styles.remove(self.index)
|
||||||
context.scene.camera.data.BIMCameraProperties.active_drawing_style_index = max(self.index - 1, 0)
|
camera_props = tool.Drawing.get_camera_props(camera_obj)
|
||||||
|
camera_props.active_drawing_style_index = max(self.index - 1, 0)
|
||||||
bpy.ops.bim.save_drawing_styles_data()
|
bpy.ops.bim.save_drawing_styles_data()
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|||||||
@@ -522,9 +522,34 @@ class BIMCameraProperties(PropertyGroup):
|
|||||||
exclude_filter_groups: CollectionProperty(type=BIMFilterGroup, name="Exclude Filter")
|
exclude_filter_groups: CollectionProperty(type=BIMFilterGroup, name="Exclude Filter")
|
||||||
update_props: BoolProperty(name="Enable Props Auto Update", default=True)
|
update_props: BoolProperty(name="Enable Props Auto Update", default=True)
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
linework_mode: Literal["OPENCASCADE", "FREESTYLE"]
|
||||||
|
fill_mode: Literal["NONE", "SHAPELY", "SVGFILL"]
|
||||||
|
cut_mode: Literal["BISECT", "OPENCASCADE"]
|
||||||
|
has_underlay: bool
|
||||||
|
has_linework: bool
|
||||||
|
has_annotation: bool
|
||||||
|
representation: str
|
||||||
|
view_name: str
|
||||||
|
diagram_scale: str
|
||||||
|
custom_scale_numerator: str
|
||||||
|
custom_scale_denominator: str
|
||||||
|
raster_x: int
|
||||||
|
raster_y: int
|
||||||
|
dpi: int
|
||||||
|
width: float
|
||||||
|
height: float
|
||||||
|
is_nts: bool
|
||||||
|
active_drawing_style_index: int
|
||||||
|
filter_mode: str
|
||||||
|
include_filter_groups: bpy.types.bpy_prop_collection_idprop[BIMFilterGroup]
|
||||||
|
exclude_filter_groups: bpy.types.bpy_prop_collection_idprop[BIMFilterGroup]
|
||||||
|
update_props: bool
|
||||||
|
|
||||||
# For now, this JSON dump are all the parameters that determine a camera's "Block representation"
|
# For now, this JSON dump are all the parameters that determine a camera's "Block representation"
|
||||||
# By checking this, you will know whether or not the camera IFC representation needs to be refreshed
|
# By checking this, you will know whether or not the camera IFC representation needs to be refreshed
|
||||||
def update_representation(self, obj):
|
def update_representation(self, obj: bpy.types.Object) -> bool:
|
||||||
|
assert isinstance(obj.data, bpy.types.Camera)
|
||||||
representation = json.dumps(
|
representation = json.dumps(
|
||||||
{
|
{
|
||||||
"matrix": [list(x) for x in obj.matrix_world],
|
"matrix": [list(x) for x in obj.matrix_world],
|
||||||
|
|||||||
@@ -1192,6 +1192,9 @@ class LinkIfc(bpy.types.Operator, ImportHelper):
|
|||||||
filepath: str
|
filepath: str
|
||||||
files: list[bpy.types.OperatorFileListElement]
|
files: list[bpy.types.OperatorFileListElement]
|
||||||
directory: str
|
directory: str
|
||||||
|
filter_glob: str
|
||||||
|
use_relative_path: bool
|
||||||
|
use_cache: bool
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
pprops = tool.Project.get_project_props()
|
pprops = tool.Project.get_project_props()
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ class Blender(bonsai.core.tool.Blender):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def activate_camera(cls, obj: bpy.types.Object) -> None:
|
def activate_camera(cls, obj: bpy.types.Object) -> None:
|
||||||
|
|
||||||
area = tool.Blender.get_view3d_area()
|
area = cls.get_view3d_area()
|
||||||
is_local_view = area.spaces[0].local_view is not None
|
is_local_view = area.spaces[0].local_view is not None
|
||||||
|
|
||||||
if is_local_view:
|
if is_local_view:
|
||||||
@@ -206,7 +206,7 @@ class Blender(bonsai.core.tool.Blender):
|
|||||||
if context is None:
|
if context is None:
|
||||||
context = bpy.context
|
context = bpy.context
|
||||||
if obj_type == "Object":
|
if obj_type == "Object":
|
||||||
props = tool.Blender.get_object_bim_props(bpy.data.objects[obj])
|
props = cls.get_object_bim_props(bpy.data.objects[obj])
|
||||||
return props.ifc_definition_id
|
return props.ifc_definition_id
|
||||||
elif obj_type == "Material":
|
elif obj_type == "Material":
|
||||||
props = tool.Material.get_material_props()
|
props = tool.Material.get_material_props()
|
||||||
@@ -239,7 +239,7 @@ class Blender(bonsai.core.tool.Blender):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_ifc_object(cls, obj: bpy.types.Object) -> bool:
|
def is_ifc_object(cls, obj: bpy.types.Object) -> bool:
|
||||||
props = tool.Blender.get_object_bim_props(obj)
|
props = cls.get_object_bim_props(obj)
|
||||||
return bool(props.ifc_definition_id)
|
return bool(props.ifc_definition_id)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -338,7 +338,7 @@ class Blender(bonsai.core.tool.Blender):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def set_viewport_tool(cls, tool_name: str) -> None:
|
def set_viewport_tool(cls, tool_name: str) -> None:
|
||||||
with bpy.context.temp_override(**tool.Blender.get_viewport_context()):
|
with bpy.context.temp_override(**cls.get_viewport_context()):
|
||||||
bpy.ops.wm.tool_set_by_id(name=tool_name)
|
bpy.ops.wm.tool_set_by_id(name=tool_name)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -398,7 +398,7 @@ class Blender(bonsai.core.tool.Blender):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def update_viewport(cls) -> None:
|
def update_viewport(cls) -> None:
|
||||||
tool.Blender.get_viewport_context()["area"].tag_redraw()
|
cls.get_viewport_context()["area"].tag_redraw()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def force_depsgraph_update(cls) -> None:
|
def force_depsgraph_update(cls) -> None:
|
||||||
@@ -711,7 +711,7 @@ class Blender(bonsai.core.tool.Blender):
|
|||||||
False if enum is still invalid (as there no enum items)
|
False if enum is still invalid (as there no enum items)
|
||||||
and update callback was not triggered (may need to trigger it manually).
|
and update callback was not triggered (may need to trigger it manually).
|
||||||
"""
|
"""
|
||||||
current_value = tool.Blender.get_enum_safe(props, prop_name)
|
current_value = cls.get_enum_safe(props, prop_name)
|
||||||
if current_value is not None:
|
if current_value is not None:
|
||||||
# Value is valid, just trigger the update callback.
|
# Value is valid, just trigger the update callback.
|
||||||
setattr(props, prop_name, current_value)
|
setattr(props, prop_name, current_value)
|
||||||
@@ -958,7 +958,7 @@ class Blender(bonsai.core.tool.Blender):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def get_layer_collection(cls, collection: bpy.types.Collection) -> Union[bpy.types.LayerCollection, None]:
|
def get_layer_collection(cls, collection: bpy.types.Collection) -> Union[bpy.types.LayerCollection, None]:
|
||||||
project = tool.Ifc.get_object(tool.Ifc.get().by_type("IfcProject")[0])
|
project = tool.Ifc.get_object(tool.Ifc.get().by_type("IfcProject")[0])
|
||||||
project_collection = tool.Blender.get_object_bim_props(project).collection
|
project_collection = cls.get_object_bim_props(project).collection
|
||||||
for layer_collection in bpy.context.view_layer.layer_collection.children:
|
for layer_collection in bpy.context.view_layer.layer_collection.children:
|
||||||
if layer_collection.collection == project_collection:
|
if layer_collection.collection == project_collection:
|
||||||
for layer_collection2 in layer_collection.children:
|
for layer_collection2 in layer_collection.children:
|
||||||
@@ -1564,7 +1564,7 @@ class Blender(bonsai.core.tool.Blender):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_user_data_dir(cls) -> Path:
|
def get_user_data_dir(cls) -> Path:
|
||||||
props = tool.Blender.get_bim_props()
|
props = cls.get_bim_props()
|
||||||
return Path(props.data_dir)
|
return Path(props.data_dir)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -1649,7 +1649,7 @@ class Blender(bonsai.core.tool.Blender):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def get_ifc_definition_id(cls, obj: IFC_CONNECTED_TYPE) -> int:
|
def get_ifc_definition_id(cls, obj: IFC_CONNECTED_TYPE) -> int:
|
||||||
if isinstance(obj, bpy.types.Object):
|
if isinstance(obj, bpy.types.Object):
|
||||||
return tool.Blender.get_object_bim_props(obj).ifc_definition_id
|
return cls.get_object_bim_props(obj).ifc_definition_id
|
||||||
return tool.Style.get_material_style_props(obj).ifc_definition_id
|
return tool.Style.get_material_style_props(obj).ifc_definition_id
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -55,7 +55,13 @@ from typing import Optional, Union, Iterable, Any, Literal, Sequence, TYPE_CHECK
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from bonsai.bim.module.drawing.prop import DocProperties, Sheet, BIMAnnotationProperties, BIMTextProperties
|
from bonsai.bim.module.drawing.prop import (
|
||||||
|
DocProperties,
|
||||||
|
Sheet,
|
||||||
|
BIMAnnotationProperties,
|
||||||
|
BIMTextProperties,
|
||||||
|
BIMCameraProperties,
|
||||||
|
)
|
||||||
from bonsai.bim.module.drawing.prop import Drawing as DrawingProperties
|
from bonsai.bim.module.drawing.prop import Drawing as DrawingProperties
|
||||||
|
|
||||||
|
|
||||||
@@ -106,6 +112,17 @@ class Drawing(bonsai.core.tool.Drawing):
|
|||||||
def get_text_props(cls, obj: bpy.types.Object) -> BIMTextProperties:
|
def get_text_props(cls, obj: bpy.types.Object) -> BIMTextProperties:
|
||||||
return obj.BIMTextProperties
|
return obj.BIMTextProperties
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_camera_props(cls, camera: Union[bpy.types.Object, bpy.types.Camera]) -> BIMCameraProperties:
|
||||||
|
"""
|
||||||
|
:param camera: Camera object or camera.
|
||||||
|
"""
|
||||||
|
if isinstance(camera, bpy.types.Camera):
|
||||||
|
data = camera
|
||||||
|
else:
|
||||||
|
assert isinstance(data := camera.data, bpy.types.Camera)
|
||||||
|
return data.BIMCameraProperties
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def canonicalise_class_name(cls, name: str) -> str:
|
def canonicalise_class_name(cls, name: str) -> str:
|
||||||
return re.sub("[^0-9a-zA-Z]+", "", name)
|
return re.sub("[^0-9a-zA-Z]+", "", name)
|
||||||
@@ -780,7 +797,7 @@ class Drawing(bonsai.core.tool.Drawing):
|
|||||||
from bonsai.bim.module.drawing.prop import get_diagram_scales
|
from bonsai.bim.module.drawing.prop import get_diagram_scales
|
||||||
|
|
||||||
# Temporarily clear the definition id to prevent prop update callbacks to IFC.
|
# Temporarily clear the definition id to prevent prop update callbacks to IFC.
|
||||||
camera_props = camera.BIMCameraProperties
|
camera_props = tool.Drawing.get_camera_props(camera)
|
||||||
update_props = camera_props.update_props
|
update_props = camera_props.update_props
|
||||||
camera_props.update_props = False
|
camera_props.update_props = False
|
||||||
|
|
||||||
@@ -2199,8 +2216,8 @@ class Drawing(bonsai.core.tool.Drawing):
|
|||||||
return float(numerator) / float(denominator)
|
return float(numerator) / float(denominator)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_diagram_scale(cls, obj: bpy.types.Object) -> dict[str, float]:
|
def get_diagram_scale(cls, obj: bpy.types.Object) -> dict[str, str]:
|
||||||
props = obj.data.BIMCameraProperties
|
props = cls.get_camera_props(obj)
|
||||||
scale = props.diagram_scale
|
scale = props.diagram_scale
|
||||||
if scale != "CUSTOM":
|
if scale != "CUSTOM":
|
||||||
human_scale, scale = scale.split("|")
|
human_scale, scale = scale.split("|")
|
||||||
|
|||||||
@@ -839,13 +839,14 @@ class Loader(bonsai.core.tool.Loader):
|
|||||||
camera = bpy.data.cameras.new(tool.Loader.get_mesh_name_from_shape(geometry))
|
camera = bpy.data.cameras.new(tool.Loader.get_mesh_name_from_shape(geometry))
|
||||||
camera.type = camera_type
|
camera.type = camera_type
|
||||||
camera.show_limits = True
|
camera.show_limits = True
|
||||||
|
props = tool.Drawing.get_camera_props(camera)
|
||||||
|
|
||||||
if camera_type == "ORTHO":
|
if camera_type == "ORTHO":
|
||||||
camera.clip_start = 0.002 # Technically 0, but Blender doesn't allow this, so 2mm it is!
|
camera.clip_start = 0.002 # Technically 0, but Blender doesn't allow this, so 2mm it is!
|
||||||
camera.clip_end = depth
|
camera.clip_end = depth
|
||||||
|
|
||||||
camera.BIMCameraProperties.width = width
|
props.width = width
|
||||||
camera.BIMCameraProperties.height = height
|
props.height = height
|
||||||
elif camera_type == "PERSP":
|
elif camera_type == "PERSP":
|
||||||
abs_min_z = abs(min(z))
|
abs_min_z = abs(min(z))
|
||||||
abs_max_z = abs(max(z))
|
abs_max_z = abs(max(z))
|
||||||
@@ -853,8 +854,8 @@ class Loader(bonsai.core.tool.Loader):
|
|||||||
camera.clip_end = abs_min_z
|
camera.clip_end = abs_min_z
|
||||||
max_res = 1000
|
max_res = 1000
|
||||||
|
|
||||||
camera.BIMCameraProperties.width = width
|
props.width = width
|
||||||
camera.BIMCameraProperties.height = height
|
props.height = height
|
||||||
|
|
||||||
if width > height:
|
if width > height:
|
||||||
fov = 2 * atan(width / (2 * abs_min_z))
|
fov = 2 * atan(width / (2 * abs_min_z))
|
||||||
|
|||||||
@@ -51,9 +51,11 @@ class Search(bonsai.core.tool.Search):
|
|||||||
elif module == "diff":
|
elif module == "diff":
|
||||||
return tool.Blender.get_diff_props().filter_groups
|
return tool.Blender.get_diff_props().filter_groups
|
||||||
elif module == "drawing_include":
|
elif module == "drawing_include":
|
||||||
return bpy.context.scene.camera.data.BIMCameraProperties.include_filter_groups
|
assert (scene := bpy.context.scene) and (camera_obj := (scene.camera))
|
||||||
|
return tool.Drawing.get_camera_props(camera_obj).include_filter_groups
|
||||||
elif module == "drawing_exclude":
|
elif module == "drawing_exclude":
|
||||||
return bpy.context.scene.camera.data.BIMCameraProperties.exclude_filter_groups
|
assert (scene := bpy.context.scene) and (camera_obj := (scene.camera))
|
||||||
|
return tool.Drawing.get_camera_props(camera_obj).exclude_filter_groups
|
||||||
elif module.startswith("clash"):
|
elif module.startswith("clash"):
|
||||||
_, clash_set_index, ab, clash_source_index = module.split("_")
|
_, clash_set_index, ab, clash_source_index = module.split("_")
|
||||||
props = tool.Clash.get_clash_props()
|
props = tool.Clash.get_clash_props()
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ from typing import Union, Optional, Literal, Any, TYPE_CHECKING
|
|||||||
from ifcopenshell.util.shape_builder import ifc_safe_vector_type, VectorType
|
from ifcopenshell.util.shape_builder import ifc_safe_vector_type, VectorType
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
import bonsai.tool as tool
|
||||||
from bonsai.bim.module.geometry.helper import Helper
|
from bonsai.bim.module.geometry.helper import Helper
|
||||||
|
|
||||||
|
|
||||||
@@ -81,9 +82,11 @@ def add_representation(
|
|||||||
"""
|
"""
|
||||||
# lazy import Helper to avoid circular import
|
# lazy import Helper to avoid circular import
|
||||||
if "Helper" not in globals():
|
if "Helper" not in globals():
|
||||||
|
import bonsai.tool as tool
|
||||||
from bonsai.bim.module.geometry.helper import Helper
|
from bonsai.bim.module.geometry.helper import Helper
|
||||||
|
|
||||||
globals()["Helper"] = Helper
|
globals()["Helper"] = Helper
|
||||||
|
globals()["tool"] = tool
|
||||||
|
|
||||||
usecase = Usecase()
|
usecase = Usecase()
|
||||||
# TODO: This usecase currently depends on Blender's data model
|
# TODO: This usecase currently depends on Blender's data model
|
||||||
@@ -111,7 +114,7 @@ class Usecase:
|
|||||||
settings: dict[str, Any]
|
settings: dict[str, Any]
|
||||||
ifc_vertices: list[ifcopenshell.entity_instance]
|
ifc_vertices: list[ifcopenshell.entity_instance]
|
||||||
coordinate_offset: Union[npt.NDArray[np.float64], None]
|
coordinate_offset: Union[npt.NDArray[np.float64], None]
|
||||||
geometry: Union[bpy.types.Mesh, bpy.types.Curve]
|
geometry: Union[bpy.types.Mesh, bpy.types.Curve, bpy.types.Camera]
|
||||||
blender_object: bpy.types.Object
|
blender_object: bpy.types.Object
|
||||||
|
|
||||||
def execute(self) -> Union[ifcopenshell.entity_instance, None]:
|
def execute(self) -> Union[ifcopenshell.entity_instance, None]:
|
||||||
@@ -319,8 +322,10 @@ class Usecase:
|
|||||||
return self.create_mesh_representation()
|
return self.create_mesh_representation()
|
||||||
|
|
||||||
def create_camera_block_representation(self) -> ifcopenshell.entity_instance:
|
def create_camera_block_representation(self) -> ifcopenshell.entity_instance:
|
||||||
raster_x = self.settings["geometry"].BIMCameraProperties.raster_x
|
assert isinstance(self.geometry, bpy.types.Camera)
|
||||||
raster_y = self.settings["geometry"].BIMCameraProperties.raster_y
|
props = tool.Drawing.get_camera_props(self.geometry)
|
||||||
|
raster_x = props.raster_x
|
||||||
|
raster_y = props.raster_y
|
||||||
|
|
||||||
if self.is_camera_landscape():
|
if self.is_camera_landscape():
|
||||||
width = self.settings["geometry"].ortho_scale
|
width = self.settings["geometry"].ortho_scale
|
||||||
@@ -347,8 +352,10 @@ class Usecase:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def create_camera_pyramid_representation(self) -> ifcopenshell.entity_instance:
|
def create_camera_pyramid_representation(self) -> ifcopenshell.entity_instance:
|
||||||
raster_x = self.settings["geometry"].BIMCameraProperties.raster_x
|
assert isinstance(self.geometry, bpy.types.Camera)
|
||||||
raster_y = self.settings["geometry"].BIMCameraProperties.raster_y
|
props = tool.Drawing.get_camera_props(self.geometry)
|
||||||
|
raster_x = props.raster_x
|
||||||
|
raster_y = props.raster_y
|
||||||
fov = self.settings["geometry"].angle
|
fov = self.settings["geometry"].angle
|
||||||
|
|
||||||
clip_end = self.settings["geometry"].clip_end
|
clip_end = self.settings["geometry"].clip_end
|
||||||
@@ -389,10 +396,9 @@ class Usecase:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def is_camera_landscape(self) -> bool:
|
def is_camera_landscape(self) -> bool:
|
||||||
return (
|
assert isinstance(self.geometry, bpy.types.Camera)
|
||||||
self.settings["geometry"].BIMCameraProperties.raster_x
|
props = tool.Drawing.get_camera_props(self.geometry)
|
||||||
> self.settings["geometry"].BIMCameraProperties.raster_y
|
return props.raster_x > props.raster_y
|
||||||
)
|
|
||||||
|
|
||||||
def create_swept_disk_solid_representation(self) -> ifcopenshell.entity_instance:
|
def create_swept_disk_solid_representation(self) -> ifcopenshell.entity_instance:
|
||||||
return self.file.createIfcShapeRepresentation(
|
return self.file.createIfcShapeRepresentation(
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import ifcopenshell
|
||||||
import datetime
|
import datetime
|
||||||
import isodate
|
import isodate
|
||||||
from re import findall
|
from re import findall
|
||||||
@@ -37,7 +38,7 @@ def timedelta2duration(timedelta):
|
|||||||
return isodate.Duration(**components)
|
return isodate.Duration(**components)
|
||||||
|
|
||||||
|
|
||||||
def ifc2datetime(element):
|
def ifc2datetime(element: Union[str, int, ifcopenshell.entity_instance]):
|
||||||
if isinstance(element, str) and "P" in element[0:2]: # IfcDuration
|
if isinstance(element, str) and "P" in element[0:2]: # IfcDuration
|
||||||
duration = parse_duration(element)
|
duration = parse_duration(element)
|
||||||
if isinstance(duration, datetime.timedelta):
|
if isinstance(duration, datetime.timedelta):
|
||||||
@@ -246,7 +247,7 @@ def parse_duration(value: Union[str, None]) -> Union[datetime.timedelta, None]:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def canonicalise_time(time):
|
def canonicalise_time(time: Union[datetime.datetime, None]) -> str:
|
||||||
if not time:
|
if not time:
|
||||||
return "-"
|
return "-"
|
||||||
return time.strftime("%d/%m/%y")
|
return time.strftime("%d/%m/%y")
|
||||||
|
|||||||
Reference in New Issue
Block a user