mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-18 22:33:33 +00:00
typing
This commit is contained in:
@@ -23,11 +23,12 @@ import bmesh
|
|||||||
import bonsai.tool as tool
|
import bonsai.tool as tool
|
||||||
import ifcopenshell.util.element
|
import ifcopenshell.util.element
|
||||||
from mathutils import Vector, Matrix
|
from mathutils import Vector, Matrix
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
class Annotator:
|
class Annotator:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def add_text(related_element=None):
|
def add_text(related_element: Optional[ifcopenshell.entity_instance] = None) -> bpy.types.Object:
|
||||||
curve = bpy.data.curves.new(type="FONT", name="Text")
|
curve = bpy.data.curves.new(type="FONT", name="Text")
|
||||||
curve.body = "TEXT"
|
curve.body = "TEXT"
|
||||||
obj = bpy.data.objects.new("Text", curve)
|
obj = bpy.data.objects.new("Text", curve)
|
||||||
@@ -53,7 +54,7 @@ class Annotator:
|
|||||||
return obj
|
return obj
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def resize_text(text_obj):
|
def resize_text(text_obj: bpy.types.Object) -> None:
|
||||||
camera = None
|
camera = None
|
||||||
group = tool.Drawing.get_drawing_group(tool.Ifc.get_entity(text_obj))
|
group = tool.Drawing.get_drawing_group(tool.Ifc.get_entity(text_obj))
|
||||||
for element in tool.Drawing.get_drawing_elements(group):
|
for element in tool.Drawing.get_drawing_elements(group):
|
||||||
@@ -71,7 +72,9 @@ class Annotator:
|
|||||||
text_obj.data.size = font_size
|
text_obj.data.size = font_size
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def add_line_to_annotation(obj, co1=None, co2=None):
|
def add_line_to_annotation(
|
||||||
|
obj: bpy.types.Object, co1: Optional[Vector] = None, co2: Optional[Vector] = None
|
||||||
|
) -> bpy.types.Object:
|
||||||
if co1 is None:
|
if co1 is None:
|
||||||
co1, co2, _, _ = Annotator.get_placeholder_coords()
|
co1, co2, _, _ = Annotator.get_placeholder_coords()
|
||||||
co1 = obj.matrix_world.inverted() @ co1
|
co1 = obj.matrix_world.inverted() @ co1
|
||||||
@@ -93,7 +96,7 @@ class Annotator:
|
|||||||
return obj
|
return obj
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def add_vertex_to_annotation(obj):
|
def add_vertex_to_annotation(obj: bpy.types.Object) -> bpy.types.Object:
|
||||||
verts_world_space = Annotator.get_placeholder_coords()
|
verts_world_space = Annotator.get_placeholder_coords()
|
||||||
vert_local = obj.matrix_world.inverted() @ verts_world_space[0]
|
vert_local = obj.matrix_world.inverted() @ verts_world_space[0]
|
||||||
bm = tool.Blender.get_bmesh_for_mesh(obj.data, clean=True)
|
bm = tool.Blender.get_bmesh_for_mesh(obj.data, clean=True)
|
||||||
@@ -102,7 +105,7 @@ class Annotator:
|
|||||||
return obj
|
return obj
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def add_plane_to_annotation(obj, remove_face=False):
|
def add_plane_to_annotation(obj: bpy.types.Object, remove_face: bool = False) -> bpy.types.Object:
|
||||||
# default order = bot left, top left, bot right, top right
|
# default order = bot left, top left, bot right, top right
|
||||||
# therefore we redefine the order
|
# therefore we redefine the order
|
||||||
face_verts = [0, 2, 3, 1]
|
face_verts = [0, 2, 3, 1]
|
||||||
@@ -119,7 +122,7 @@ class Annotator:
|
|||||||
return obj
|
return obj
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_annotation_obj(drawing, object_type, data_type):
|
def get_annotation_obj(drawing: ifcopenshell.entity_instance, object_type: str, data_type: str) -> bpy.types.Object:
|
||||||
camera = tool.Ifc.get_object(drawing)
|
camera = tool.Ifc.get_object(drawing)
|
||||||
co1, _, _, _ = Annotator.get_placeholder_coords(camera)
|
co1, _, _, _ = Annotator.get_placeholder_coords(camera)
|
||||||
matrix_world = tool.Drawing.get_camera_matrix(camera)
|
matrix_world = tool.Drawing.get_camera_matrix(camera)
|
||||||
@@ -162,7 +165,7 @@ class Annotator:
|
|||||||
return obj
|
return obj
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_placeholder_coords(camera=None):
|
def get_placeholder_coords(camera: Optional[bpy.types.Object] = None) -> tuple[Vector, Vector, Vector, Vector]:
|
||||||
if not camera:
|
if not camera:
|
||||||
camera = bpy.context.scene.camera
|
camera = bpy.context.scene.camera
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import bonsai.core.root
|
|||||||
from bonsai.bim.module.model.window import create_bm_window, create_bm_box
|
from bonsai.bim.module.model.window import create_bm_window, create_bm_box
|
||||||
|
|
||||||
from mathutils import Vector, Matrix
|
from mathutils import Vector, Matrix
|
||||||
|
from typing import Union, Any, Optional
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import collections
|
import collections
|
||||||
@@ -169,7 +170,9 @@ def update_door_modifier_representation(context: bpy.types.Context) -> None:
|
|||||||
|
|
||||||
|
|
||||||
# TODO: move it out to tools
|
# TODO: move it out to tools
|
||||||
def bm_sort_out_geom(geom_data):
|
def bm_sort_out_geom(
|
||||||
|
geom_data: list[Union[bmesh.types.BMVert, bmesh.types.BMEdge, bmesh.types.BMFace]]
|
||||||
|
) -> dict[str, Any]:
|
||||||
geom_dict = {"verts": [], "edges": [], "faces": []}
|
geom_dict = {"verts": [], "edges": [], "faces": []}
|
||||||
|
|
||||||
for el in geom_data:
|
for el in geom_data:
|
||||||
@@ -183,8 +186,12 @@ def bm_sort_out_geom(geom_data):
|
|||||||
|
|
||||||
|
|
||||||
def bm_mirror(
|
def bm_mirror(
|
||||||
bm, verts, mirror_axes: Vector = V(1, 0, 0).freeze(), mirror_point: Vector = V(0, 0, 0).freeze(), create_copy=False
|
bm: bmesh.types.BMesh,
|
||||||
):
|
verts: list[bmesh.types.BMVert],
|
||||||
|
mirror_axes: Vector = V(1, 0, 0).freeze(),
|
||||||
|
mirror_point: Vector = V(0, 0, 0).freeze(),
|
||||||
|
create_copy: bool = False,
|
||||||
|
) -> list[bmesh.types.BMVert]:
|
||||||
matrix = Matrix.Translation(mirror_point)
|
matrix = Matrix.Translation(mirror_point)
|
||||||
for i, v in enumerate(mirror_axes):
|
for i, v in enumerate(mirror_axes):
|
||||||
if not v:
|
if not v:
|
||||||
@@ -208,14 +215,14 @@ def bm_mirror(
|
|||||||
|
|
||||||
|
|
||||||
def create_bm_extruded_profile(
|
def create_bm_extruded_profile(
|
||||||
bm,
|
bm: bmesh.types.BMesh,
|
||||||
points,
|
points: list[Vector],
|
||||||
edges=None,
|
edges: Optional[list[tuple[int, int]]] = None,
|
||||||
faces=None,
|
faces: Optional[list[list[int]]] = None,
|
||||||
position: Vector = V(0, 0, 0).freeze(),
|
position: Vector = V(0, 0, 0).freeze(),
|
||||||
magnitude=1.0,
|
magnitude: float = 1.0,
|
||||||
extrusion_vector: Vector = V(0, 0, 1).freeze(),
|
extrusion_vector: Vector = V(0, 0, 1).freeze(),
|
||||||
):
|
) -> list[bmesh.types.BMVert]:
|
||||||
bm.verts.index_update()
|
bm.verts.index_update()
|
||||||
bm.edges.index_update()
|
bm.edges.index_update()
|
||||||
bm.faces.ensure_lookup_table()
|
bm.faces.ensure_lookup_table()
|
||||||
@@ -242,7 +249,9 @@ def create_bm_extruded_profile(
|
|||||||
return new_verts + extruded_verts
|
return new_verts + extruded_verts
|
||||||
|
|
||||||
|
|
||||||
def create_bm_door_lining(bm, size: Vector, thickness: list, position: Vector = V(0, 0, 0).freeze()):
|
def create_bm_door_lining(
|
||||||
|
bm: bmesh.types.BMesh, size: Vector, thickness: list, position: Vector = V(0, 0, 0).freeze()
|
||||||
|
) -> list[bmesh.types.BMVert]:
|
||||||
"""`thickness` of the profile is defined as list in the following order: `(SIDE, TOP)`
|
"""`thickness` of the profile is defined as list in the following order: `(SIDE, TOP)`
|
||||||
|
|
||||||
`thickness` can be also defined just as 1 float value.
|
`thickness` can be also defined just as 1 float value.
|
||||||
@@ -303,7 +312,7 @@ def create_bm_door_lining(bm, size: Vector, thickness: list, position: Vector =
|
|||||||
return new_verts + translate_verts
|
return new_verts + translate_verts
|
||||||
|
|
||||||
|
|
||||||
def update_door_modifier_bmesh(context):
|
def update_door_modifier_bmesh(context: bpy.types.Context) -> None:
|
||||||
obj = context.active_object
|
obj = context.active_object
|
||||||
props = obj.BIMDoorProperties
|
props = obj.BIMDoorProperties
|
||||||
|
|
||||||
@@ -400,7 +409,9 @@ def update_door_modifier_bmesh(context):
|
|||||||
inner_casing_verts = create_bm_door_lining(bm, casing_size, inner_casing_thickness, inner_casing_position)
|
inner_casing_verts = create_bm_door_lining(bm, casing_size, inner_casing_thickness, inner_casing_position)
|
||||||
casing_verts.extend(inner_casing_verts)
|
casing_verts.extend(inner_casing_verts)
|
||||||
|
|
||||||
def create_bm_door_panel(panel_size, panel_position, door_swing_type):
|
def create_bm_door_panel(
|
||||||
|
panel_size: Vector, panel_position: Vector, door_swing_type: str
|
||||||
|
) -> list[bmesh.types.BMVert]:
|
||||||
door_verts = []
|
door_verts = []
|
||||||
# add door panel
|
# add door panel
|
||||||
door_verts.extend(create_bm_box(bm, panel_size, panel_position))
|
door_verts.extend(create_bm_box(bm, panel_size, panel_position))
|
||||||
|
|||||||
@@ -33,13 +33,14 @@ from bonsai.bim.module.model.decorator import ProfileDecorator
|
|||||||
|
|
||||||
from mathutils import Vector
|
from mathutils import Vector
|
||||||
import json
|
import json
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
# reference:
|
# reference:
|
||||||
# https://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcRailing.htm
|
# https://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcRailing.htm
|
||||||
# https://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcRailingType.htm
|
# https://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcRailingType.htm
|
||||||
|
|
||||||
|
|
||||||
def bm_split_edge_at_offset(edge, offset):
|
def bm_split_edge_at_offset(edge: bmesh.types.BMEdge, offset: float) -> dict[str, Any]:
|
||||||
v0, v1 = edge.verts
|
v0, v1 = edge.verts
|
||||||
|
|
||||||
offset = offset / 2
|
offset = offset / 2
|
||||||
@@ -51,7 +52,7 @@ def bm_split_edge_at_offset(edge, offset):
|
|||||||
return new_geometry
|
return new_geometry
|
||||||
|
|
||||||
|
|
||||||
def update_railing_modifier_ifc_data(context):
|
def update_railing_modifier_ifc_data(context: bpy.types.Context) -> None:
|
||||||
"""should be called after new geometry settled
|
"""should be called after new geometry settled
|
||||||
since it's going to update ifc representation
|
since it's going to update ifc representation
|
||||||
"""
|
"""
|
||||||
@@ -113,7 +114,7 @@ def update_railing_modifier_ifc_data(context):
|
|||||||
tool.Ifc.edit(obj)
|
tool.Ifc.edit(obj)
|
||||||
|
|
||||||
|
|
||||||
def update_bbim_railing_pset(element, railing_data):
|
def update_bbim_railing_pset(element: ifcopenshell.entity_instance, railing_data: dict[str, Any]) -> None:
|
||||||
pset = tool.Pset.get_element_pset(element, "BBIM_Railing")
|
pset = tool.Pset.get_element_pset(element, "BBIM_Railing")
|
||||||
if not pset:
|
if not pset:
|
||||||
pset = ifcopenshell.api.run("pset.add_pset", tool.Ifc.get(), product=element, name="BBIM_Railing")
|
pset = ifcopenshell.api.run("pset.add_pset", tool.Ifc.get(), product=element, name="BBIM_Railing")
|
||||||
@@ -121,7 +122,7 @@ def update_bbim_railing_pset(element, railing_data):
|
|||||||
ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=pset, properties={"Data": railing_data})
|
ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=pset, properties={"Data": railing_data})
|
||||||
|
|
||||||
|
|
||||||
def update_railing_modifier_bmesh(context):
|
def update_railing_modifier_bmesh(context: bpy.types.Context) -> None:
|
||||||
"""before using should make sure that Data contains up-to-date information.
|
"""before using should make sure that Data contains up-to-date information.
|
||||||
If BBIM Pset just changed should call refresh() before updating bmesh
|
If BBIM Pset just changed should call refresh() before updating bmesh
|
||||||
"""
|
"""
|
||||||
@@ -153,7 +154,7 @@ def update_railing_modifier_bmesh(context):
|
|||||||
if props.railing_type != "FRAMELESS_PANEL":
|
if props.railing_type != "FRAMELESS_PANEL":
|
||||||
return
|
return
|
||||||
|
|
||||||
def generate_frameless_panel_railing():
|
def generate_frameless_panel_railing() -> None:
|
||||||
# generating FRAMELESS_PANEL railing
|
# generating FRAMELESS_PANEL railing
|
||||||
height = props.height
|
height = props.height
|
||||||
thickness = props.thickness
|
thickness = props.thickness
|
||||||
@@ -214,7 +215,7 @@ def update_railing_modifier_bmesh(context):
|
|||||||
generate_frameless_panel_railing()
|
generate_frameless_panel_railing()
|
||||||
|
|
||||||
|
|
||||||
def get_path_data(obj):
|
def get_path_data(obj: bpy.types.Object) -> dict[str, Any]:
|
||||||
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||||
|
|
||||||
bm = tool.Blender.get_bmesh_for_mesh(obj.data)
|
bm = tool.Blender.get_bmesh_for_mesh(obj.data)
|
||||||
@@ -468,7 +469,7 @@ class EnableEditingRailingPath(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
def cancel_editing_railing_path(context):
|
def cancel_editing_railing_path(context: bpy.types.Context) -> set[str]:
|
||||||
obj = context.active_object
|
obj = context.active_object
|
||||||
props = obj.BIMRailingProperties
|
props = obj.BIMRailingProperties
|
||||||
|
|
||||||
|
|||||||
@@ -37,13 +37,14 @@ import mathutils.geometry
|
|||||||
from bpypolyskel import bpypolyskel
|
from bpypolyskel import bpypolyskel
|
||||||
import shapely
|
import shapely
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
|
from typing import Literal, Union, Any
|
||||||
|
|
||||||
# reference:
|
# reference:
|
||||||
# https://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcRoof.htm
|
# https://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcRoof.htm
|
||||||
# https://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcRoofType.htm
|
# https://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcRoofType.htm
|
||||||
|
|
||||||
|
|
||||||
def bm_mesh_clean_up(bm):
|
def bm_mesh_clean_up(bm: bmesh.types.BMesh) -> None:
|
||||||
# remove internal edges and faces
|
# remove internal edges and faces
|
||||||
# adding missing faces so we could rely on `e.is_boundary` later
|
# adding missing faces so we could rely on `e.is_boundary` later
|
||||||
bmesh.ops.contextual_create(bm, geom=bm.edges[:])
|
bmesh.ops.contextual_create(bm, geom=bm.edges[:])
|
||||||
@@ -94,7 +95,7 @@ class GenerateHippedRoof(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
def is_valid_roof_footprint(bm):
|
def is_valid_roof_footprint(bm: bmesh.types.BMesh) -> tuple[set[str], str]:
|
||||||
# should be bmesh to support edit mode
|
# should be bmesh to support edit mode
|
||||||
bm.verts.ensure_lookup_table()
|
bm.verts.ensure_lookup_table()
|
||||||
base_z = bm.verts[0].co.z
|
base_z = bm.verts[0].co.z
|
||||||
@@ -108,8 +109,14 @@ def is_valid_roof_footprint(bm):
|
|||||||
|
|
||||||
|
|
||||||
def generate_hiped_roof_bmesh(
|
def generate_hiped_roof_bmesh(
|
||||||
bm, mode="ANGLE", height=1.0, roof_thickness=0.1, angle=pi / 18, rafter_edge_angle=pi / 2, mutate_current_bmesh=True
|
bm: bmesh.types.BMesh,
|
||||||
):
|
mode: Literal["ANGLE", "HEIGHT"] = "ANGLE",
|
||||||
|
height: float = 1.0,
|
||||||
|
roof_thickness: float = 0.1,
|
||||||
|
angle: float = pi / 18,
|
||||||
|
rafter_edge_angle: float = pi / 2,
|
||||||
|
mutate_current_bmesh: float = True,
|
||||||
|
) -> bmesh.types.BMesh:
|
||||||
"""return bmesh with gable roof geometry
|
"""return bmesh with gable roof geometry
|
||||||
|
|
||||||
`mutate_current_bmesh` is a flag to indicate whether the input bmesh
|
`mutate_current_bmesh` is a flag to indicate whether the input bmesh
|
||||||
@@ -199,16 +206,16 @@ def generate_hiped_roof_bmesh(
|
|||||||
new_edges = [bm.edges.new([new_verts[vi] for vi in edge]) for edge in edges]
|
new_edges = [bm.edges.new([new_verts[vi] for vi in edge]) for edge in edges]
|
||||||
new_faces = [bm.faces.new([new_verts[vi] for vi in face]) for face in faces]
|
new_faces = [bm.faces.new([new_verts[vi] for vi in face]) for face in faces]
|
||||||
|
|
||||||
def find_identical_new_vert(co):
|
def find_identical_new_vert(co: Vector) -> Union[bmesh.types.BMVert, None]:
|
||||||
for v in bm.verts:
|
for v in bm.verts:
|
||||||
if tool.Cad.is_x((co - v.co).length, 0):
|
if tool.Cad.is_x((co - v.co).length, 0):
|
||||||
return v
|
return v
|
||||||
|
|
||||||
def find_other_polygon_verts(edge):
|
def find_other_polygon_verts(edge: bmesh.types.BMEdge) -> list[bmesh.types.BMVert]:
|
||||||
polygon = edge.link_faces[0]
|
polygon = edge.link_faces[0]
|
||||||
return [v for v in polygon.verts if v not in edge.verts]
|
return [v for v in polygon.verts if v not in edge.verts]
|
||||||
|
|
||||||
def change_angle(projected_vert_co, edge_verts, new_angle):
|
def change_angle(projected_vert_co: Vector, edge_verts: list[bmesh.types.BMVert], new_angle: float) -> Vector:
|
||||||
A, B = [v.co for v in edge_verts]
|
A, B = [v.co for v in edge_verts]
|
||||||
P = projected_vert_co
|
P = projected_vert_co
|
||||||
|
|
||||||
@@ -232,10 +239,10 @@ def generate_hiped_roof_bmesh(
|
|||||||
verts_to_rip = []
|
verts_to_rip = []
|
||||||
bottom_chords_to_remove = []
|
bottom_chords_to_remove = []
|
||||||
|
|
||||||
def is_footprint_vert(v):
|
def is_footprint_vert(v: bmesh.types.BMVert) -> bool:
|
||||||
return tool.Cad.is_x(v.co.z - footprint_z, 0)
|
return tool.Cad.is_x(v.co.z - footprint_z, 0)
|
||||||
|
|
||||||
def is_footprint_edge(edge):
|
def is_footprint_edge(edge: bmesh.types.BMEdge) -> bool:
|
||||||
return all(is_footprint_vert(v) for v in edge.verts)
|
return all(is_footprint_vert(v) for v in edge.verts)
|
||||||
|
|
||||||
# find footprint edges
|
# find footprint edges
|
||||||
@@ -279,7 +286,9 @@ def generate_hiped_roof_bmesh(
|
|||||||
if defined_angle >= pi / 2:
|
if defined_angle >= pi / 2:
|
||||||
bottom_chords_to_remove.append(identical_edge)
|
bottom_chords_to_remove.append(identical_edge)
|
||||||
|
|
||||||
def separate_vert(bm, vert, edge, new_co):
|
def separate_vert(
|
||||||
|
bm: bmesh.types.BMesh, vert: bmesh.types.BMVert, edge: bmesh.types.BMEdge, new_co: Vector
|
||||||
|
) -> bmesh.types.BMVert:
|
||||||
face = next(f for f in vert.link_faces if edge in f.edges)
|
face = next(f for f in vert.link_faces if edge in f.edges)
|
||||||
new_v = bmesh.utils.face_vert_separate(face, vert)
|
new_v = bmesh.utils.face_vert_separate(face, vert)
|
||||||
new_v.co = new_co
|
new_v.co = new_co
|
||||||
@@ -378,11 +387,11 @@ def generate_hiped_roof_bmesh(
|
|||||||
return bm
|
return bm
|
||||||
|
|
||||||
|
|
||||||
def bm_get_indices(sequence):
|
def bm_get_indices(sequence) -> list[int]:
|
||||||
return [i.index for i in sequence]
|
return [i.index for i in sequence]
|
||||||
|
|
||||||
|
|
||||||
def update_roof_modifier_ifc_data(context):
|
def update_roof_modifier_ifc_data(context: bpy.types.Context) -> None:
|
||||||
"""should be called after new geometry settled
|
"""should be called after new geometry settled
|
||||||
since it's going to update ifc representation
|
since it's going to update ifc representation
|
||||||
"""
|
"""
|
||||||
@@ -390,7 +399,7 @@ def update_roof_modifier_ifc_data(context):
|
|||||||
props = obj.BIMRoofProperties
|
props = obj.BIMRoofProperties
|
||||||
element = tool.Ifc.get_entity(obj)
|
element = tool.Ifc.get_entity(obj)
|
||||||
|
|
||||||
def roof_is_gabled():
|
def roof_is_gabled() -> bool:
|
||||||
pset_data = tool.Model.get_modeling_bbim_pset_data(obj, "BBIM_Roof")
|
pset_data = tool.Model.get_modeling_bbim_pset_data(obj, "BBIM_Roof")
|
||||||
path_data = pset_data["data_dict"]["path_data"]
|
path_data = pset_data["data_dict"]["path_data"]
|
||||||
angle_layer = path_data.get("gable_roof_angles", None)
|
angle_layer = path_data.get("gable_roof_angles", None)
|
||||||
@@ -411,7 +420,7 @@ def update_roof_modifier_ifc_data(context):
|
|||||||
tool.Ifc.edit(obj)
|
tool.Ifc.edit(obj)
|
||||||
|
|
||||||
|
|
||||||
def update_bbim_roof_pset(element, roof_data):
|
def update_bbim_roof_pset(element: ifcopenshell.entity_instance, roof_data: dict[str, Any]) -> None:
|
||||||
pset = tool.Pset.get_element_pset(element, "BBIM_Roof")
|
pset = tool.Pset.get_element_pset(element, "BBIM_Roof")
|
||||||
if not pset:
|
if not pset:
|
||||||
pset = ifcopenshell.api.run("pset.add_pset", tool.Ifc.get(), product=element, name="BBIM_Roof")
|
pset = ifcopenshell.api.run("pset.add_pset", tool.Ifc.get(), product=element, name="BBIM_Roof")
|
||||||
@@ -419,7 +428,7 @@ def update_bbim_roof_pset(element, roof_data):
|
|||||||
ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=pset, properties={"Data": roof_data})
|
ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=pset, properties={"Data": roof_data})
|
||||||
|
|
||||||
|
|
||||||
def update_roof_modifier_bmesh(context):
|
def update_roof_modifier_bmesh(context: bpy.types.Context) -> None:
|
||||||
"""before using should make sure that Data contains up-to-date information.
|
"""before using should make sure that Data contains up-to-date information.
|
||||||
If BBIM Pset just changed should call refresh() before updating bmesh
|
If BBIM Pset just changed should call refresh() before updating bmesh
|
||||||
"""
|
"""
|
||||||
@@ -466,7 +475,7 @@ def update_roof_modifier_bmesh(context):
|
|||||||
tool.Blender.apply_bmesh(obj.data, bm)
|
tool.Blender.apply_bmesh(obj.data, bm)
|
||||||
|
|
||||||
|
|
||||||
def get_path_data(obj):
|
def get_path_data(obj: bpy.types.Object) -> Union[dict[str, Any], None]:
|
||||||
"""get path data for current mesh, path data is cleaned up"""
|
"""get path data for current mesh, path data is cleaned up"""
|
||||||
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||||
|
|
||||||
@@ -699,7 +708,7 @@ class EnableEditingRoofPath(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
def cancel_editing_roof_path(context):
|
def cancel_editing_roof_path(context: bpy.types.Context) -> set[str]:
|
||||||
obj = context.active_object
|
obj = context.active_object
|
||||||
props = obj.BIMRoofProperties
|
props = obj.BIMRoofProperties
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ from bpy.props import FloatProperty, IntProperty
|
|||||||
from bpy_extras.object_utils import AddObjectHelper, object_data_add
|
from bpy_extras.object_utils import AddObjectHelper, object_data_add
|
||||||
|
|
||||||
|
|
||||||
def regenerate_stair_mesh(context):
|
def regenerate_stair_mesh(context: bpy.types.Context) -> None:
|
||||||
obj = context.active_object
|
obj = context.active_object
|
||||||
props_kwargs = obj.BIMStairProperties.get_props_kwargs()
|
props_kwargs = obj.BIMStairProperties.get_props_kwargs()
|
||||||
vertices, edges, faces = tool.Model.generate_stair_2d_profile(**props_kwargs)
|
vertices, edges, faces = tool.Model.generate_stair_2d_profile(**props_kwargs)
|
||||||
@@ -65,7 +65,7 @@ def regenerate_stair_mesh(context):
|
|||||||
obj.data.update()
|
obj.data.update()
|
||||||
|
|
||||||
|
|
||||||
def update_ifc_stair_props(obj):
|
def update_ifc_stair_props(obj: bpy.types.Object) -> None:
|
||||||
"""should be called after new geometry settled
|
"""should be called after new geometry settled
|
||||||
since it's going to update ifc representation
|
since it's going to update ifc representation
|
||||||
"""
|
"""
|
||||||
@@ -114,7 +114,7 @@ def update_ifc_stair_props(obj):
|
|||||||
tool.Ifc.edit(obj)
|
tool.Ifc.edit(obj)
|
||||||
|
|
||||||
# update related annotation objects
|
# update related annotation objects
|
||||||
def get_elements_from_product(product):
|
def get_elements_from_product(product: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_instance]:
|
||||||
elements = []
|
elements = []
|
||||||
for rel in product.ReferencedBy:
|
for rel in product.ReferencedBy:
|
||||||
if not rel.is_a("IfcRelAssignsToProduct"):
|
if not rel.is_a("IfcRelAssignsToProduct"):
|
||||||
|
|||||||
@@ -34,9 +34,10 @@ import ifcopenshell.util.unit
|
|||||||
from ifcopenshell.util.shape_builder import V
|
from ifcopenshell.util.shape_builder import V
|
||||||
from bmesh.types import BMVert
|
from bmesh.types import BMVert
|
||||||
from mathutils import Vector
|
from mathutils import Vector
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
def update_window_modifier_representation(context):
|
def update_window_modifier_representation(context: bpy.types.Context) -> None:
|
||||||
obj = context.active_object
|
obj = context.active_object
|
||||||
element = tool.Ifc.get_entity(obj)
|
element = tool.Ifc.get_entity(obj)
|
||||||
props = obj.BIMWindowProperties
|
props = obj.BIMWindowProperties
|
||||||
@@ -129,7 +130,9 @@ def update_window_modifier_representation(context):
|
|||||||
tool.Model.update_simple_openings(element)
|
tool.Model.update_simple_openings(element)
|
||||||
|
|
||||||
|
|
||||||
def create_bm_window_frame(bm, size: Vector, thickness: list, position: Vector = V(0, 0, 0).freeze()):
|
def create_bm_window_frame(
|
||||||
|
bm: bmesh.types.BMesh, size: Vector, thickness: list, position: Vector = V(0, 0, 0).freeze()
|
||||||
|
) -> list[bmesh.types.BMVert]:
|
||||||
"""`thickness` of the profile is defined as list in the following order:
|
"""`thickness` of the profile is defined as list in the following order:
|
||||||
`(LEFT, TOP, RIGHT, BOTTOM)`
|
`(LEFT, TOP, RIGHT, BOTTOM)`
|
||||||
|
|
||||||
@@ -194,7 +197,9 @@ def create_bm_window_frame(bm, size: Vector, thickness: list, position: Vector =
|
|||||||
return new_verts + translate_verts
|
return new_verts + translate_verts
|
||||||
|
|
||||||
|
|
||||||
def create_bm_box(bm, size: Vector = V(1, 1, 1).freeze(), position: Vector = V(0, 0, 0).freeze()):
|
def create_bm_box(
|
||||||
|
bm: bmesh.types.BMesh, size: Vector = V(1, 1, 1).freeze(), position: Vector = V(0, 0, 0).freeze()
|
||||||
|
) -> list[bmesh.types.BMVert]:
|
||||||
"""create a box of `size`, position box first vertex at `position`"""
|
"""create a box of `size`, position box first vertex at `position`"""
|
||||||
box_verts = bmesh.ops.create_cube(bm, size=1)["verts"]
|
box_verts = bmesh.ops.create_cube(bm, size=1)["verts"]
|
||||||
bmesh.ops.translate(bm, vec=-box_verts[0].co, verts=box_verts)
|
bmesh.ops.translate(bm, vec=-box_verts[0].co, verts=box_verts)
|
||||||
@@ -204,17 +209,17 @@ def create_bm_box(bm, size: Vector = V(1, 1, 1).freeze(), position: Vector = V(0
|
|||||||
|
|
||||||
|
|
||||||
def create_bm_window(
|
def create_bm_window(
|
||||||
bm,
|
bm: bmesh.types.BMesh,
|
||||||
lining_size: Vector,
|
lining_size: Vector,
|
||||||
lining_thickness: list,
|
lining_thickness: list,
|
||||||
lining_to_panel_offset_x,
|
lining_to_panel_offset_x,
|
||||||
lining_to_panel_offset_y_full,
|
lining_to_panel_offset_y_full,
|
||||||
frame_size: Vector,
|
frame_size: Vector,
|
||||||
frame_thickness,
|
frame_thickness: float,
|
||||||
glass_thickness,
|
glass_thickness: float,
|
||||||
position: Vector,
|
position: Vector,
|
||||||
x_offsets: list = None,
|
x_offsets: Optional[list] = None,
|
||||||
):
|
) -> tuple[list[bmesh.types.BMVert], list[bmesh.types.BMVert], list[bmesh.types.BMVert]]:
|
||||||
"""`lining_thickness` and `x_offsets` are expected to be defined as a list,
|
"""`lining_thickness` and `x_offsets` are expected to be defined as a list,
|
||||||
similarly to `create_bm_window_frame` `thickness` argument"""
|
similarly to `create_bm_window_frame` `thickness` argument"""
|
||||||
|
|
||||||
@@ -241,7 +246,7 @@ def create_bm_window(
|
|||||||
return (window_lining_verts, frame_verts, glass_verts)
|
return (window_lining_verts, frame_verts, glass_verts)
|
||||||
|
|
||||||
|
|
||||||
def update_window_modifier_bmesh(context):
|
def update_window_modifier_bmesh(context: bpy.types.Context) -> None:
|
||||||
obj = context.active_object
|
obj = context.active_object
|
||||||
props = obj.BIMWindowProperties
|
props = obj.BIMWindowProperties
|
||||||
panel_schema = DEFAULT_PANEL_SCHEMAS[props.window_type]
|
panel_schema = DEFAULT_PANEL_SCHEMAS[props.window_type]
|
||||||
|
|||||||
@@ -35,32 +35,32 @@ from bpy.props import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_export_schema(self, context):
|
def get_export_schema(self: "BIMProjectProperties", context: bpy.types.Context) -> list[tuple[str, str, str]]:
|
||||||
if not ProjectData.is_loaded:
|
if not ProjectData.is_loaded:
|
||||||
ProjectData.load()
|
ProjectData.load()
|
||||||
return ProjectData.data["export_schema"]
|
return ProjectData.data["export_schema"]
|
||||||
|
|
||||||
|
|
||||||
def get_template_file(self, context):
|
def get_template_file(self: "BIMProjectProperties", context: bpy.types.Context) -> list[tuple[str, str, str]]:
|
||||||
if not ProjectData.is_loaded:
|
if not ProjectData.is_loaded:
|
||||||
ProjectData.load()
|
ProjectData.load()
|
||||||
return ProjectData.data["template_file"]
|
return ProjectData.data["template_file"]
|
||||||
|
|
||||||
|
|
||||||
def get_library_file(self, context):
|
def get_library_file(self: "BIMProjectProperties", context: bpy.types.Context) -> list[tuple[str, str, str]]:
|
||||||
if not ProjectData.is_loaded:
|
if not ProjectData.is_loaded:
|
||||||
ProjectData.load()
|
ProjectData.load()
|
||||||
return ProjectData.data["library_file"]
|
return ProjectData.data["library_file"]
|
||||||
|
|
||||||
|
|
||||||
def update_library_file(self, context):
|
def update_library_file(self: "BIMProjectProperties", context: bpy.types.Context) -> None:
|
||||||
if self.library_file != "0":
|
if self.library_file != "0":
|
||||||
bpy.ops.bim.select_library_file(
|
bpy.ops.bim.select_library_file(
|
||||||
filepath=os.path.join(bpy.context.scene.BIMProperties.data_dir, "libraries", self.library_file)
|
filepath=os.path.join(bpy.context.scene.BIMProperties.data_dir, "libraries", self.library_file)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def update_filter_mode(self, context):
|
def update_filter_mode(self: "BIMProjectProperties", context: bpy.types.Context) -> None:
|
||||||
self.filter_categories.clear()
|
self.filter_categories.clear()
|
||||||
if self.filter_mode == "NONE":
|
if self.filter_mode == "NONE":
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -248,7 +248,12 @@ class Model(bonsai.core.tool.Model):
|
|||||||
return obj
|
return obj
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def import_profile(cls, profile, obj=None, position=None):
|
def import_profile(
|
||||||
|
cls,
|
||||||
|
profile: ifcopenshell.entity_instance,
|
||||||
|
obj: Optional[bpy.types.Object] = None,
|
||||||
|
position: Optional[Matrix] = None,
|
||||||
|
) -> bpy.types.Object:
|
||||||
"""Creates new profile mesh and assigns it to `obj`,
|
"""Creates new profile mesh and assigns it to `obj`,
|
||||||
if `obj` is `None` then new "Profile" object will be created.
|
if `obj` is `None` then new "Profile" object will be created.
|
||||||
|
|
||||||
@@ -297,7 +302,9 @@ class Model(bonsai.core.tool.Model):
|
|||||||
return obj
|
return obj
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def import_surface(cls, surface, obj=None):
|
def import_surface(
|
||||||
|
cls, surface: ifcopenshell.entity_instance, obj: Optional[bpy.types.Object] = None
|
||||||
|
) -> bpy.types.Object:
|
||||||
cls.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
cls.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||||
|
|
||||||
cls.vertices = []
|
cls.vertices = []
|
||||||
@@ -333,7 +340,7 @@ class Model(bonsai.core.tool.Model):
|
|||||||
return obj
|
return obj
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def import_curve(cls, obj, position, curve):
|
def import_curve(cls, obj: bpy.types.Object, position: Matrix, curve: ifcopenshell.entity_instance) -> None:
|
||||||
offset = len(cls.vertices)
|
offset = len(cls.vertices)
|
||||||
|
|
||||||
if curve.is_a("IfcPolyline"):
|
if curve.is_a("IfcPolyline"):
|
||||||
@@ -402,7 +409,7 @@ class Model(bonsai.core.tool.Model):
|
|||||||
cls.edges.append((offset, offset + 1))
|
cls.edges.append((offset, offset + 1))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def import_rectangle(cls, obj, position, profile):
|
def import_rectangle(cls, obj: bpy.types.Object, position: Matrix, profile: ifcopenshell.entity_instance) -> None:
|
||||||
if profile.Position:
|
if profile.Position:
|
||||||
p_position = Matrix(ifcopenshell.util.placement.get_axis2placement(profile.Position).tolist())
|
p_position = Matrix(ifcopenshell.util.placement.get_axis2placement(profile.Position).tolist())
|
||||||
p_position.translation *= cls.unit_scale
|
p_position.translation *= cls.unit_scale
|
||||||
@@ -424,7 +431,7 @@ class Model(bonsai.core.tool.Model):
|
|||||||
cls.edges[-1] = (len(cls.vertices) - 1, 0) # Close the loop
|
cls.edges[-1] = (len(cls.vertices) - 1, 0) # Close the loop
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load_openings(cls, openings):
|
def load_openings(cls, openings: list[ifcopenshell.entity_instance]) -> Iterable[bpy.types.Object]:
|
||||||
if not openings:
|
if not openings:
|
||||||
return []
|
return []
|
||||||
ifc_import_settings = import_ifc.IfcImportSettings.factory()
|
ifc_import_settings = import_ifc.IfcImportSettings.factory()
|
||||||
@@ -476,7 +483,11 @@ class Model(bonsai.core.tool.Model):
|
|||||||
}
|
}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_booleans(cls, element=None, representation=None) -> list[ifcopenshell.entity_instance]:
|
def get_booleans(
|
||||||
|
cls,
|
||||||
|
element: Optional[ifcopenshell.entity_instance] = None,
|
||||||
|
representation: Optional[ifcopenshell.entity_instance] = None,
|
||||||
|
) -> list[ifcopenshell.entity_instance]:
|
||||||
if representation is None:
|
if representation is None:
|
||||||
representation = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
|
representation = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
|
||||||
if not representation:
|
if not representation:
|
||||||
@@ -491,7 +502,9 @@ class Model(bonsai.core.tool.Model):
|
|||||||
return booleans
|
return booleans
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_manual_booleans(cls, element, representation=None) -> list[ifcopenshell.entity_instance]:
|
def get_manual_booleans(
|
||||||
|
cls, element: ifcopenshell.entity_instance, representation: Optional[ifcopenshell.entity_instance] = None
|
||||||
|
) -> list[ifcopenshell.entity_instance]:
|
||||||
pset = ifcopenshell.util.element.get_pset(element, "BBIM_Boolean")
|
pset = ifcopenshell.util.element.get_pset(element, "BBIM_Boolean")
|
||||||
if not pset:
|
if not pset:
|
||||||
return []
|
return []
|
||||||
@@ -521,7 +534,7 @@ class Model(bonsai.core.tool.Model):
|
|||||||
ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=pset, properties={"Data": data})
|
ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=pset, properties={"Data": data})
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def unmark_manual_booleans(cls, element, boolean_ids):
|
def unmark_manual_booleans(cls, element: ifcopenshell.entity_instance, boolean_ids: list[int]) -> None:
|
||||||
# NOTE: we use use boolean_ids instead of boolean entities
|
# NOTE: we use use boolean_ids instead of boolean entities
|
||||||
# so it will be possible to unmark manual booleans after they already was deleted
|
# so it will be possible to unmark manual booleans after they already was deleted
|
||||||
pset = ifcopenshell.util.element.get_pset(element, "BBIM_Boolean")
|
pset = ifcopenshell.util.element.get_pset(element, "BBIM_Boolean")
|
||||||
@@ -538,12 +551,14 @@ class Model(bonsai.core.tool.Model):
|
|||||||
ifcopenshell.api.run("pset.remove_pset", tool.Ifc.get(), product=element, pset=pset)
|
ifcopenshell.api.run("pset.remove_pset", tool.Ifc.get(), product=element, pset=pset)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_flow_segment_axis(cls, obj):
|
def get_flow_segment_axis(cls, obj: bpy.types.Object) -> tuple[Vector, Vector]:
|
||||||
z_values = [v[2] for v in obj.bound_box]
|
z_values = [v[2] for v in obj.bound_box]
|
||||||
return (obj.matrix_world @ Vector((0, 0, min(z_values))), obj.matrix_world @ Vector((0, 0, max(z_values))))
|
return (obj.matrix_world @ Vector((0, 0, min(z_values))), obj.matrix_world @ Vector((0, 0, max(z_values))))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_flow_segment_profile(cls, element):
|
def get_flow_segment_profile(
|
||||||
|
cls, element: ifcopenshell.entity_instance
|
||||||
|
) -> Union[ifcopenshell.entity_instance, None]:
|
||||||
material = ifcopenshell.util.element.get_material(element, should_skip_usage=True)
|
material = ifcopenshell.util.element.get_material(element, should_skip_usage=True)
|
||||||
if material and material.is_a("IfcMaterialProfileSet") and len(material.MaterialProfiles) == 1:
|
if material and material.is_a("IfcMaterialProfileSet") and len(material.MaterialProfiles) == 1:
|
||||||
return material.MaterialProfiles[0].Profile
|
return material.MaterialProfiles[0].Profile
|
||||||
@@ -579,7 +594,7 @@ class Model(bonsai.core.tool.Model):
|
|||||||
return "PROFILE"
|
return "PROFILE"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_wall_axis(cls, obj, layers=None):
|
def get_wall_axis(cls, obj: bpy.types.Object, layers: Optional[dict[str, Any]] = None) -> dict[str, Any]:
|
||||||
x_values = [v[0] for v in obj.bound_box]
|
x_values = [v[0] for v in obj.bound_box]
|
||||||
min_x = min(x_values)
|
min_x = min(x_values)
|
||||||
max_x = max(x_values)
|
max_x = max(x_values)
|
||||||
@@ -602,7 +617,9 @@ class Model(bonsai.core.tool.Model):
|
|||||||
return axes
|
return axes
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def handle_array_on_copied_element(cls, element, array_data=None):
|
def handle_array_on_copied_element(
|
||||||
|
cls, element: ifcopenshell.entity_instance, array_data: Optional[dict[str, Any]] = None
|
||||||
|
) -> None:
|
||||||
"""if no `array_data` is provided then an array will be removed from the element"""
|
"""if no `array_data` is provided then an array will be removed from the element"""
|
||||||
|
|
||||||
if array_data is None:
|
if array_data is None:
|
||||||
@@ -647,7 +664,9 @@ class Model(bonsai.core.tool.Model):
|
|||||||
tool.Blender.Modifier.Array.constrain_children_to_parent(element)
|
tool.Blender.Modifier.Array.constrain_children_to_parent(element)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def regenerate_array(cls, parent_obj, data, array_layers_to_apply=tuple()):
|
def regenerate_array(
|
||||||
|
cls, parent_obj: bpy.types.Object, data: list[dict[str, Any]], array_layers_to_apply: Iterable[int] = tuple()
|
||||||
|
) -> None:
|
||||||
"""`array_layers_to_apply` - list of array layer indices to apply"""
|
"""`array_layers_to_apply` - list of array layer indices to apply"""
|
||||||
tool.Blender.Modifier.Array.remove_constraints(tool.Ifc.get_entity(parent_obj))
|
tool.Blender.Modifier.Array.remove_constraints(tool.Ifc.get_entity(parent_obj))
|
||||||
|
|
||||||
@@ -744,7 +763,12 @@ class Model(bonsai.core.tool.Model):
|
|||||||
bpy.context.view_layer.update()
|
bpy.context.view_layer.update()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def replace_object_ifc_representation(cls, ifc_context, obj, new_representation):
|
def replace_object_ifc_representation(
|
||||||
|
cls,
|
||||||
|
ifc_context: ifcopenshell.entity_instance,
|
||||||
|
obj: bpy.types.Object,
|
||||||
|
new_representation: ifcopenshell.entity_instance,
|
||||||
|
) -> None:
|
||||||
ifc_file = tool.Ifc.get()
|
ifc_file = tool.Ifc.get()
|
||||||
ifc_element = tool.Ifc.get_entity(obj)
|
ifc_element = tool.Ifc.get_entity(obj)
|
||||||
old_representation = ifcopenshell.util.representation.get_representation(
|
old_representation = ifcopenshell.util.representation.get_representation(
|
||||||
@@ -771,7 +795,7 @@ class Model(bonsai.core.tool.Model):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def update_thumbnail_for_element(cls, element, refresh=False):
|
def update_thumbnail_for_element(cls, element: ifcopenshell.entity_instance, refresh: bool = False) -> None:
|
||||||
if bpy.app.background:
|
if bpy.app.background:
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -877,7 +901,7 @@ class Model(bonsai.core.tool.Model):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_modeling_bbim_pset_data(cls, object, pset_name):
|
def get_modeling_bbim_pset_data(cls, object: bpy.types.Object, pset_name: str) -> Union[dict[str, Any], None]:
|
||||||
"""get modelling BBIM pset data (eg, BBIM_Roof) and loads it's `Data` as json to `data_dict`"""
|
"""get modelling BBIM pset data (eg, BBIM_Roof) and loads it's `Data` as json to `data_dict`"""
|
||||||
element = tool.Ifc.get_entity(object)
|
element = tool.Ifc.get_entity(object)
|
||||||
if not element:
|
if not element:
|
||||||
@@ -890,7 +914,7 @@ class Model(bonsai.core.tool.Model):
|
|||||||
return pset_data
|
return pset_data
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def edit_element_placement(cls, element, matrix):
|
def edit_element_placement(cls, element: ifcopenshell.entity_instance, matrix: Matrix) -> None:
|
||||||
"""Useful for moving objects like ports or openings -
|
"""Useful for moving objects like ports or openings -
|
||||||
the method will ensure it will be moved in blender scene too if it exists"""
|
the method will ensure it will be moved in blender scene too if it exists"""
|
||||||
obj = tool.Ifc.get_object(element)
|
obj = tool.Ifc.get_object(element)
|
||||||
@@ -900,13 +924,13 @@ class Model(bonsai.core.tool.Model):
|
|||||||
tool.Ifc.run("geometry.edit_object_placement", product=element, matrix=matrix, is_si=True)
|
tool.Ifc.run("geometry.edit_object_placement", product=element, matrix=matrix, is_si=True)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def sync_object_ifc_position(cls, obj):
|
def sync_object_ifc_position(cls, obj: bpy.types.Object) -> None:
|
||||||
"""make sure IFC position will be in sync with the Blender object position, if object was moved in Blender"""
|
"""make sure IFC position will be in sync with the Blender object position, if object was moved in Blender"""
|
||||||
if tool.Ifc.is_moved(obj):
|
if tool.Ifc.is_moved(obj):
|
||||||
bonsai.core.geometry.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=obj)
|
bonsai.core.geometry.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=obj)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_element_matrix(cls, element, keep_local=False):
|
def get_element_matrix(cls, element: ifcopenshell.entity_instance, keep_local: bool = False) -> Matrix:
|
||||||
placement = element.ObjectPlacement
|
placement = element.ObjectPlacement
|
||||||
if keep_local:
|
if keep_local:
|
||||||
placement = ifcopenshell.util.placement.get_axis2placement(placement.RelativePlacement)
|
placement = ifcopenshell.util.placement.get_axis2placement(placement.RelativePlacement)
|
||||||
@@ -947,23 +971,23 @@ class Model(bonsai.core.tool.Model):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_parametric_roof_active(cls):
|
def is_parametric_roof_active(cls) -> bool:
|
||||||
return (RoofData.is_loaded or not RoofData.load()) and RoofData.data["pset_data"]
|
return bool((RoofData.is_loaded or not RoofData.load()) and RoofData.data["pset_data"])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_parametric_railing_active(cls):
|
def is_parametric_railing_active(cls) -> bool:
|
||||||
return (RailingData.is_loaded or not RailingData.load()) and RailingData.data["pset_data"]
|
return bool((RailingData.is_loaded or not RailingData.load()) and RailingData.data["pset_data"])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_parametric_window_active(cls):
|
def is_parametric_window_active(cls) -> bool:
|
||||||
return (WindowData.is_loaded or not WindowData.load()) and WindowData.data["pset_data"]
|
return bool((WindowData.is_loaded or not WindowData.load()) and WindowData.data["pset_data"])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_parametric_door_active(cls):
|
def is_parametric_door_active(cls) -> bool:
|
||||||
return (DoorData.is_loaded or not DoorData.load()) and DoorData.data["pset_data"]
|
return bool((DoorData.is_loaded or not DoorData.load()) and DoorData.data["pset_data"])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_active_stair_calculated_params(cls, pset_data=None):
|
def get_active_stair_calculated_params(cls, pset_data: Optional[dict[str, Any]] = None) -> dict[str, Any]:
|
||||||
props = bpy.context.active_object.BIMStairProperties
|
props = bpy.context.active_object.BIMStairProperties
|
||||||
|
|
||||||
if props.is_editing:
|
if props.is_editing:
|
||||||
|
|||||||
Reference in New Issue
Block a user