Polyline wall ability to switch axis while drawing.

While drawing the polyline the user can press:
- F to flip the wall. Changes the direction sense.
- O to change the offset type between Exterior, Center and Interior. This will change the offset from reference line.

Those attributes can be verified in the Object Materials panels of each wall after they are created.
This commit is contained in:
Bruno Perdigão
2024-10-15 21:54:19 -03:00
parent d7bf8eba02
commit b9c6508aa7
4 changed files with 101 additions and 23 deletions
@@ -165,13 +165,13 @@ class PolylineOperator:
self.tool_state.axis_method = None self.tool_state.axis_method = None
tool.Blender.update_viewport() tool.Blender.update_viewport()
def handle_instructions(self, context): def handle_instructions(self, context, custom_instructions):
self.snap_info = f"""| self.snap_info = f"""|
Axis: {self.tool_state.axis_method} Axis: {self.tool_state.axis_method}
Plane: {self.tool_state.plane_method} Plane: {self.tool_state.plane_method}
Snap: {self.snapping_points[0][1]} Snap: {self.snapping_points[0][1]}
""" """
context.workspace.status_text_set(self.instructions + self.snap_info) context.workspace.status_text_set(self.instructions + custom_instructions + self.snap_info)
def handle_lock_axis(self, context, event): def handle_lock_axis(self, context, event):
if event.value == "RELEASE" and event.type == "L": if event.value == "RELEASE" and event.type == "L":
@@ -149,6 +149,18 @@ class BIMModelProperties(PropertyGroup):
type_page: bpy.props.IntProperty(name="Type Page", default=1, update=update_type_page) type_page: bpy.props.IntProperty(name="Type Page", default=1, update=update_type_page)
type_name: bpy.props.StringProperty(name="Name", default="TYPEX") type_name: bpy.props.StringProperty(name="Name", default="TYPEX")
boundary_class: bpy.props.EnumProperty(items=get_boundary_class, name="Boundary Class") boundary_class: bpy.props.EnumProperty(items=get_boundary_class, name="Boundary Class")
direction_sense: bpy.props.EnumProperty(
items=[("POSITIVE", "Positive", ""), ("NEGATIVE", "Negative", "")],
name="Material Usage Direction Sense",
default="POSITIVE"
)
offset_type: bpy.props.EnumProperty(
items=[("EXTERIOR", "Exterior", ""), ("CENTER", "Center", ""), ("INTERIOR", "Interior", "")],
name="Layer Offset Type",
default="EXTERIOR",
description="It's a convention that affects the offset to reference line"
)
offset: bpy.props.FloatProperty(name="Offset", default=0.0, description="Material usage offset from reference line")
class BIMArrayProperties(PropertyGroup): class BIMArrayProperties(PropertyGroup):
+42 -2
View File
@@ -297,7 +297,8 @@ class DrawPolylineWall(bpy.types.Operator, PolylineOperator):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.relating_type = None self.relating_type = None
relating_type_id = bpy.context.scene.BIMModelProperties.relating_type_id props = bpy.context.scene.BIMModelProperties
relating_type_id = props.relating_type_id
if relating_type_id: if relating_type_id:
self.relating_type = tool.Ifc.get().by_id(int(relating_type_id)) self.relating_type = tool.Ifc.get().by_id(int(relating_type_id))
@@ -305,7 +306,25 @@ class DrawPolylineWall(bpy.types.Operator, PolylineOperator):
if not self.relating_type: if not self.relating_type:
return {"FINISHED"} return {"FINISHED"}
model_props = context.scene.BIMModelProperties
direction_sense = model_props.direction_sense
offset = model_props.offset
walls, is_polyline_closed = DumbWallGenerator(self.relating_type).generate(True) walls, is_polyline_closed = DumbWallGenerator(self.relating_type).generate(True)
for wall in walls:
model = IfcStore.get_file()
element = tool.Ifc.get_entity(wall["obj"])
material = ifcopenshell.util.element.get_material(element)
material_set_usage = model.by_id(material.id())
# if material.is_a("IfcMaterialLayerSetUsage"):
attributes = {"OffsetFromReferenceLine": offset, "DirectionSense": direction_sense}
ifcopenshell.api.run(
"material.edit_layer_usage",
model,
**{"usage": material_set_usage, "attributes": attributes},
)
DumbWallRecalculator().recalculate([wall["obj"]])
if walls: if walls:
if is_polyline_closed: if is_polyline_closed:
for wall1, wall2 in zip(walls, walls[1:] + [walls[0]]): for wall1, wall2 in zip(walls, walls[1:] + [walls[0]]):
@@ -330,7 +349,28 @@ class DrawPolylineWall(bpy.types.Operator, PolylineOperator):
self.handle_mouse_move(context, event) self.handle_mouse_move(context, event)
return {"PASS_THROUGH"} return {"PASS_THROUGH"}
self.handle_instructions(context) # Wall axis settings
if event.value == "RELEASE" and event.type == "F":
direction_sense = context.scene.BIMModelProperties.direction_sense
context.scene.BIMModelProperties.direction_sense = (
"NEGATIVE" if direction_sense == "POSITIVE" else "POSITIVE"
)
tool.Polyline.create_wall_preview_vertices(context, self.relating_type)
if event.value == "RELEASE" and event.type == "O":
offset_type = context.scene.BIMModelProperties.offset_type
items = ["EXTERIOR", "CENTER", "INTERIOR"]
index = items.index(offset_type)
size = len(items)
context.scene.BIMModelProperties.offset_type = items[((index + 1) % size)]
tool.Polyline.create_wall_preview_vertices(context, self.relating_type)
props = bpy.context.scene.BIMModelProperties
wall_config = f"""Direction: {props.direction_sense}
Offset Type: {props.offset_type}
Offset Value: {props.offset}
"""
self.handle_instructions(context, wall_config)
self.handle_mouse_move(context, event, should_round=True) self.handle_mouse_move(context, event, should_round=True)
+45 -19
View File
@@ -309,7 +309,7 @@ class Polyline(bonsai.core.tool.Polyline):
def create_bmesh_from_vertices(vertices): def create_bmesh_from_vertices(vertices):
bm = bmesh.new() bm = bmesh.new()
new_verts = [bm.verts.new(v) for v in base_vertices] new_verts = [bm.verts.new(v) for v in polyline_vertices]
if is_closed: if is_closed:
new_edges = [bm.edges.new((new_verts[i], new_verts[i + 1])) for i in range(len(new_verts) - 1)] new_edges = [bm.edges.new((new_verts[i], new_verts[i + 1])) for i in range(len(new_verts) - 1)]
new_edges.append( new_edges.append(
@@ -327,36 +327,61 @@ class Polyline(bonsai.core.tool.Polyline):
if not layers["thickness"]: if not layers["thickness"]:
return return
thickness = layers["thickness"] thickness = layers["thickness"]
model_props = context.scene.BIMModelProperties
direction_sense = model_props.direction_sense
direction = 1
if direction_sense == "NEGATIVE":
direction = -1
offset_type = model_props.offset_type
offset = 0
if offset_type == "CENTER":
offset = -thickness/2
elif offset_type == "INTERIOR":
offset = -thickness
height = float(context.scene.BIMModelProperties.extrusion_depth) unit_system = tool.Drawing.get_unit_system()
rl = float(context.scene.BIMModelProperties.rl1) factor = 1
x_angle = float(context.scene.BIMModelProperties.x_angle) if unit_system == "IMPERIAL":
factor = 3.048
if unit_system == "METRIC":
unit_length = bpy.context.scene.unit_settings.length_unit
if unit_length == "MILLIMETERS":
factor = 1000
# For the model properties, the offset value should just be converted
# However, for the wall preview logic that follows, offset and thickness must change direction
model_props.offset = offset * factor
thickness *= direction
offset *= direction
height = float(model_props.extrusion_depth)
rl = float(model_props.rl1)
x_angle = float(model_props.x_angle)
angle_distortion = height * tan(x_angle) angle_distortion = height * tan(x_angle)
base_vertices = [] polyline_vertices = []
top_vertices = []
polyline_data = context.scene.BIMPolylineProperties.insertion_polyline polyline_data = context.scene.BIMPolylineProperties.insertion_polyline
polyline_points = polyline_data[0].polyline_points if polyline_data else [] polyline_points = polyline_data[0].polyline_points if polyline_data else []
if len(polyline_points) < 2: if len(polyline_points) < 2:
context.scene.BIMPolylineProperties.product_preview.clear() context.scene.BIMPolylineProperties.product_preview.clear()
return return
for point in polyline_points: for point in polyline_points:
base_vertices.append(Vector((point.x, point.y, point.z))) polyline_vertices.append(Vector((point.x, point.y, point.z)))
is_closed = False is_closed = False
if ( if (
base_vertices[0].x == base_vertices[-1].x polyline_vertices[0].x == polyline_vertices[-1].x
and base_vertices[0].y == base_vertices[-1].y and polyline_vertices[0].y == polyline_vertices[-1].y
and base_vertices[0].z == base_vertices[-1].z and polyline_vertices[0].z == polyline_vertices[-1].z
): ):
is_closed = True is_closed = True
base_vertices.pop(-1) # Remove the last point. The edges are going to inform that the shape is closed. polyline_vertices.pop(-1) # Remove the last point. The edges are going to inform that the shape is closed.
bm_base = create_bmesh_from_vertices(base_vertices) bm_base = create_bmesh_from_vertices(polyline_vertices)
base_vertices = tool.Cad.offset_edges(bm_base, offset)
offset_base_verts = tool.Cad.offset_edges(bm_base, thickness) offset_base_verts = tool.Cad.offset_edges(bm_base, thickness + offset)
top_vertices = tool.Cad.offset_edges(bm_base, angle_distortion) top_vertices = tool.Cad.offset_edges(bm_base, angle_distortion + offset)
offset_top_verts = tool.Cad.offset_edges(bm_base, angle_distortion + thickness) offset_top_verts = tool.Cad.offset_edges(bm_base, angle_distortion + thickness + offset)
if is_closed: if is_closed:
base_vertices.append(base_vertices[0]) base_vertices.append(base_vertices[0])
@@ -367,10 +392,11 @@ class Polyline(bonsai.core.tool.Polyline):
if offset_base_verts is not None: if offset_base_verts is not None:
context.scene.BIMPolylineProperties.product_preview.clear() context.scene.BIMPolylineProperties.product_preview.clear()
for v in base_vertices: for v in base_vertices:
new_v = Vector((v.co.x, v.co.y, v.co.z))
prop = context.scene.BIMPolylineProperties.product_preview.add() prop = context.scene.BIMPolylineProperties.product_preview.add()
prop.x = v.x prop.x = new_v.x
prop.y = v.y prop.y = new_v.y
prop.z = v.z + rl prop.z = new_v.z + rl
for v in offset_base_verts[::-1]: for v in offset_base_verts[::-1]:
new_v = Vector((v.co.x, v.co.y, v.co.z)) new_v = Vector((v.co.x, v.co.y, v.co.z))