Door handles

This commit is contained in:
Andrej730
2023-02-10 16:55:13 +05:00
parent 13f5767921
commit 3654e49f87
3 changed files with 148 additions and 10 deletions
@@ -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