mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-21 14:23:53 +00:00
Door handles
This commit is contained in:
@@ -19,10 +19,8 @@
|
|||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
from bpy.types import Operator
|
from bpy.types import Operator
|
||||||
from bpy.props import FloatProperty, IntProperty, BoolProperty
|
|
||||||
from bpy_extras.object_utils import AddObjectHelper, object_data_add
|
|
||||||
import bmesh
|
import bmesh
|
||||||
from bmesh.types import BMVert
|
from bmesh.types import BMVert, BMFace
|
||||||
|
|
||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
import blenderbim
|
import blenderbim
|
||||||
@@ -33,11 +31,9 @@ from blenderbim.bim.ifc import IfcStore
|
|||||||
from blenderbim.bim.module.model.window import create_bm_window, create_bm_box
|
from blenderbim.bim.module.model.window import create_bm_window, create_bm_box
|
||||||
from blenderbim.bim.module.model.helper import get_ifc_context_or_create, replace_ifc_representation_for_object
|
from blenderbim.bim.module.model.helper import get_ifc_context_or_create, replace_ifc_representation_for_object
|
||||||
|
|
||||||
|
from mathutils import Vector, Matrix
|
||||||
from mathutils import Vector
|
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
|
|
||||||
from os.path import basename, dirname
|
|
||||||
import json
|
import json
|
||||||
import collections
|
import collections
|
||||||
|
|
||||||
@@ -112,6 +108,81 @@ def update_door_modifier_representation(context):
|
|||||||
ifc_element.OperationType = props.door_type
|
ifc_element.OperationType = props.door_type
|
||||||
|
|
||||||
|
|
||||||
|
def bm_sort_out_geom(geom_data):
|
||||||
|
geom_dict = {
|
||||||
|
'verts': [],
|
||||||
|
'edges': [],
|
||||||
|
'faces': []
|
||||||
|
}
|
||||||
|
|
||||||
|
for el in geom_data:
|
||||||
|
if isinstance(el, BMVert):
|
||||||
|
geom_dict['verts'].append(el)
|
||||||
|
elif isinstance(el, BMFace):
|
||||||
|
geom_dict['faces'].append(el)
|
||||||
|
else:
|
||||||
|
geom_dict['edges'].append(el)
|
||||||
|
return geom_dict
|
||||||
|
|
||||||
|
|
||||||
|
def bm_mirror(bm, verts,
|
||||||
|
mirror_axes: Vector = V(1,0,0).freeze(),
|
||||||
|
mirror_point: Vector = V(0,0,0).freeze(),
|
||||||
|
create_copy=False):
|
||||||
|
|
||||||
|
matrix = Matrix.Translation(mirror_point)
|
||||||
|
for i, v in enumerate(mirror_axes):
|
||||||
|
if not v:
|
||||||
|
continue
|
||||||
|
mirror_axis = V(0,0,0)
|
||||||
|
mirror_axis[i] = 1.0
|
||||||
|
matrix = matrix @ Matrix.Scale(-1, 4, mirror_axis)
|
||||||
|
matrix = matrix @ Matrix.Translation(-mirror_point)
|
||||||
|
|
||||||
|
# `bmesh.ops.mirror` has no option to mirror existing geometry without creating new
|
||||||
|
# and matrix kind of work diffrently than transform so I chose `bmesh.ops.transform`
|
||||||
|
if create_copy:
|
||||||
|
faces = set()
|
||||||
|
for v in verts: faces.update(v.link_faces)
|
||||||
|
duplicated = bmesh.ops.duplicate(bm, geom=list(faces))
|
||||||
|
verts = bm_sort_out_geom(duplicated['geom'])['verts']
|
||||||
|
|
||||||
|
bmesh.ops.transform(bm, verts=verts, matrix=matrix, space=Matrix.Identity(4))
|
||||||
|
return verts
|
||||||
|
|
||||||
|
|
||||||
|
def create_bm_extruded_profile(
|
||||||
|
bm, points, edges=None, faces=None,
|
||||||
|
position: Vector = V(0,0,0).freeze(),
|
||||||
|
magnitude=1.0,
|
||||||
|
extrusion_vector: Vector = V(0,0,1).freeze()
|
||||||
|
):
|
||||||
|
bm.verts.index_update()
|
||||||
|
bm.edges.index_update()
|
||||||
|
bm.faces.ensure_lookup_table()
|
||||||
|
|
||||||
|
if not edges:
|
||||||
|
last_point = len(points) - 1
|
||||||
|
edges = [(i, i+1) for i in range(last_point)]
|
||||||
|
edges.append((last_point, 0))
|
||||||
|
|
||||||
|
new_verts = [bm.verts.new(v) for v in points]
|
||||||
|
new_edges = [bm.edges.new([new_verts[vi] for vi in edge]) for edge in edges]
|
||||||
|
|
||||||
|
if not faces:
|
||||||
|
new_faces = bmesh.ops.contextual_create(bm, geom=new_edges)['faces']
|
||||||
|
else:
|
||||||
|
new_faces = [bm.faces.new([new_verts[vi] for vi in face]) for face in faces]
|
||||||
|
|
||||||
|
extruded = bmesh.ops.extrude_face_region(bm, geom=new_faces)
|
||||||
|
extrusion_vector = extrusion_vector * magnitude
|
||||||
|
extruded_verts = bm_sort_out_geom(extruded['geom'])['verts']
|
||||||
|
bmesh.ops.translate(bm, vec=extrusion_vector, verts=extruded_verts)
|
||||||
|
|
||||||
|
bmesh.ops.translate(bm, vec=position, verts=new_verts + extruded_verts)
|
||||||
|
return new_verts + extruded_verts
|
||||||
|
|
||||||
|
|
||||||
def create_bm_door_lining(bm, size: Vector, thickness: Vector, position:Vector=V(0,0,0).freeze()):
|
def create_bm_door_lining(bm, size: Vector, thickness: Vector, position:Vector=V(0,0,0).freeze()):
|
||||||
"""`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)`
|
||||||
|
|
||||||
@@ -180,6 +251,7 @@ def update_door_modifier_bmesh(context):
|
|||||||
|
|
||||||
overall_width = props.overall_width * si_conversion
|
overall_width = props.overall_width * si_conversion
|
||||||
overall_height = props.overall_height * si_conversion
|
overall_height = props.overall_height * si_conversion
|
||||||
|
door_type = props.door_type
|
||||||
|
|
||||||
# lining params
|
# lining params
|
||||||
lining_depth = props.lining_depth * si_conversion
|
lining_depth = props.lining_depth * si_conversion
|
||||||
@@ -215,6 +287,12 @@ def update_door_modifier_bmesh(context):
|
|||||||
frame_height = window_lining_height - lining_to_panel_offset_x * 2
|
frame_height = window_lining_height - lining_to_panel_offset_x * 2
|
||||||
glass_thickness = 0.01 * si_conversion
|
glass_thickness = 0.01 * si_conversion
|
||||||
|
|
||||||
|
# handle dimensions (hardcoded)
|
||||||
|
handle_size = V(120, 40, 20) * 0.001 * si_conversion
|
||||||
|
handle_offset = V(60, 0, 1000) * 0.001 * si_conversion # to the handle center
|
||||||
|
handle_center_offset = V(handle_size.y/2, 0, handle_size.z)/2
|
||||||
|
|
||||||
|
|
||||||
if transfom_offset:
|
if transfom_offset:
|
||||||
panel_height = transfom_offset + transom_thickness - lining_to_panel_offset_x - threshold_thickness
|
panel_height = transfom_offset + transom_thickness - lining_to_panel_offset_x - threshold_thickness
|
||||||
lining_height = transfom_offset + transom_thickness
|
lining_height = transfom_offset + transom_thickness
|
||||||
@@ -259,6 +337,34 @@ def update_door_modifier_bmesh(context):
|
|||||||
panel_position = V(lining_to_panel_offset_x, lining_to_panel_offset_y, threshold_thickness)
|
panel_position = V(lining_to_panel_offset_x, lining_to_panel_offset_y, threshold_thickness)
|
||||||
panel_verts = create_bm_box(bm, panel_size, panel_position)
|
panel_verts = create_bm_box(bm, panel_size, panel_position)
|
||||||
|
|
||||||
|
# add door handle
|
||||||
|
door_handles_verts = []
|
||||||
|
handle_points = [
|
||||||
|
V(0, 0, 0),
|
||||||
|
V(0, -handle_size.y, 0),
|
||||||
|
V(handle_size.x, -handle_size.y, 0),
|
||||||
|
V(handle_size.x, -handle_size.y/2, 0),
|
||||||
|
V(handle_size.y/2, -handle_size.y/2, 0),
|
||||||
|
V(handle_size.y/2, 0, 0),
|
||||||
|
]
|
||||||
|
handle_position = panel_position + handle_offset - handle_center_offset
|
||||||
|
door_handle_verts = create_bm_extruded_profile(bm, handle_points,
|
||||||
|
magnitude=handle_size.z,
|
||||||
|
position=handle_position)
|
||||||
|
door_handles_verts.extend(door_handle_verts)
|
||||||
|
|
||||||
|
if door_type == 'SINGLE_SWING_LEFT':
|
||||||
|
bm_mirror(bm, door_handle_verts,
|
||||||
|
mirror_axes=V(1,0,0),
|
||||||
|
mirror_point=panel_position + V(panel_size.x/2, 0, 0))
|
||||||
|
|
||||||
|
door_handle_mirrored_verts = bm_mirror(bm, door_handle_verts,
|
||||||
|
mirror_axes=V(0, 1, 0),
|
||||||
|
mirror_point=handle_position + V(0, panel_size.y/2, 0),
|
||||||
|
create_copy=True)
|
||||||
|
door_handles_verts.extend(door_handle_mirrored_verts)
|
||||||
|
|
||||||
|
|
||||||
# add on top window
|
# add on top window
|
||||||
if not transom_thickness:
|
if not transom_thickness:
|
||||||
window_lining_verts = []
|
window_lining_verts = []
|
||||||
|
|||||||
@@ -28,13 +28,11 @@ import blenderbim.core.geometry
|
|||||||
from ifcopenshell.api.geometry.add_window_representation import DEFAULT_PANEL_SCHEMAS
|
from ifcopenshell.api.geometry.add_window_representation import DEFAULT_PANEL_SCHEMAS
|
||||||
from bpy.types import Operator
|
from bpy.types import Operator
|
||||||
from bpy.props import FloatProperty, IntProperty, BoolProperty
|
from bpy.props import FloatProperty, IntProperty, BoolProperty
|
||||||
from bpy_extras.object_utils import AddObjectHelper, object_data_add
|
|
||||||
from bmesh.types import BMVert
|
from bmesh.types import BMVert
|
||||||
from blenderbim.bim.helper import convert_property_group_from_si
|
from blenderbim.bim.helper import convert_property_group_from_si
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from blenderbim.bim.module.model.helper import replace_ifc_representation_for_object
|
from blenderbim.bim.module.model.helper import replace_ifc_representation_for_object
|
||||||
from mathutils import Vector
|
from mathutils import Vector
|
||||||
from os.path import basename, dirname
|
|
||||||
|
|
||||||
|
|
||||||
V = lambda *x: Vector([float(i) for i in x])
|
V = lambda *x: Vector([float(i) for i in x])
|
||||||
|
|||||||
@@ -180,6 +180,11 @@ class Usecase:
|
|||||||
frame_height = window_lining_height - lining_to_panel_offset_x * 2
|
frame_height = window_lining_height - lining_to_panel_offset_x * 2
|
||||||
glass_thickness = self.convert_si_to_unit(0.01)
|
glass_thickness = self.convert_si_to_unit(0.01)
|
||||||
|
|
||||||
|
# handle dimensions (hardcoded)
|
||||||
|
handle_size = self.convert_si_to_unit(V(120, 40, 20) * 0.001)
|
||||||
|
handle_offset = self.convert_si_to_unit(V(60, 0, 1000) * 0.001) # to the handle center
|
||||||
|
handle_center_offset = V(handle_size.y/2, 0, handle_size.z)/2
|
||||||
|
|
||||||
if transfom_offset:
|
if transfom_offset:
|
||||||
panel_height = transfom_offset + transom_thickness - lining_to_panel_offset_x - threshold_thickness
|
panel_height = transfom_offset + transom_thickness - lining_to_panel_offset_x - threshold_thickness
|
||||||
lining_height = transfom_offset + transom_thickness
|
lining_height = transfom_offset + transom_thickness
|
||||||
@@ -290,6 +295,32 @@ class Usecase:
|
|||||||
panel_position = V(lining_to_panel_offset_x, lining_to_panel_offset_y_full, threshold_thickness)
|
panel_position = V(lining_to_panel_offset_x, lining_to_panel_offset_y_full, threshold_thickness)
|
||||||
panel_items = [create_ifc_box(builder, panel_size, panel_position)]
|
panel_items = [create_ifc_box(builder, panel_size, panel_position)]
|
||||||
|
|
||||||
|
# add door handle
|
||||||
|
door_handles_items = []
|
||||||
|
handle_points = [
|
||||||
|
V(0, 0),
|
||||||
|
V(0, -handle_size.y),
|
||||||
|
V(handle_size.x, -handle_size.y),
|
||||||
|
V(handle_size.x, -handle_size.y/2),
|
||||||
|
V(handle_size.y/2, -handle_size.y/2),
|
||||||
|
V(handle_size.y/2, 0),
|
||||||
|
]
|
||||||
|
handle_polyline = builder.polyline(handle_points, closed=True)
|
||||||
|
|
||||||
|
handle_position = panel_position + handle_offset - handle_center_offset
|
||||||
|
|
||||||
|
door_handle = builder.extrude(handle_polyline, handle_size.z, position=handle_position)
|
||||||
|
door_handles_items.append(door_handle)
|
||||||
|
|
||||||
|
if door_type == 'SINGLE_SWING_LEFT':
|
||||||
|
builder.mirror(door_handle, mirror_axes=V(1,0),
|
||||||
|
mirror_point=panel_position.xy + V(panel_size.x/2, 0))
|
||||||
|
|
||||||
|
door_handle_mirrored = builder.mirror(door_handle, mirror_axes=V(0, 1),
|
||||||
|
mirror_point=handle_position.xy + V(0, panel_size.y/2),
|
||||||
|
create_copy=True)
|
||||||
|
door_handles_items.append(door_handle_mirrored)
|
||||||
|
|
||||||
# add on top window
|
# add on top window
|
||||||
if not transom_thickness:
|
if not transom_thickness:
|
||||||
window_lining_items = []
|
window_lining_items = []
|
||||||
@@ -313,7 +344,7 @@ class Usecase:
|
|||||||
window_position,
|
window_position,
|
||||||
)
|
)
|
||||||
|
|
||||||
lining_offset_items = lining_items + panel_items + window_lining_items + frame_items + glass_items
|
lining_offset_items = lining_items + panel_items + window_lining_items + frame_items + glass_items + door_handles_items
|
||||||
builder.translate(lining_offset_items, V(0, lining_offset, 0))
|
builder.translate(lining_offset_items, V(0, lining_offset, 0))
|
||||||
|
|
||||||
output_items = lining_offset_items + threshold_items + casing_items
|
output_items = lining_offset_items + threshold_items + casing_items
|
||||||
@@ -322,4 +353,7 @@ class Usecase:
|
|||||||
return representation
|
return representation
|
||||||
|
|
||||||
def convert_si_to_unit(self, value):
|
def convert_si_to_unit(self, value):
|
||||||
return value / self.settings["unit_scale"]
|
si_conversion = 1 / self.settings["unit_scale"]
|
||||||
|
if isinstance(value, Vector):
|
||||||
|
return V(*[i*si_conversion for i in value])
|
||||||
|
return value * si_conversion
|
||||||
|
|||||||
Reference in New Issue
Block a user