Make slab's editing profile to horizontal orientation when x_angle is present.

This commit is contained in:
Bruno Perdigão
2025-01-27 15:16:22 -03:00
parent 47b2a00614
commit a4a52d6576
2 changed files with 48 additions and 9 deletions
+36 -2
View File
@@ -646,14 +646,31 @@ class EnableEditingExtrusionProfile(bpy.types.Operator, tool.Ifc.Operator):
body = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
body = ifcopenshell.util.representation.resolve_representation(body)
extrusion = tool.Model.get_extrusion(body)
existing_x_angle = tool.Model.get_existing_x_angle(extrusion)
layer_params = tool.Model.get_material_layer_parameters(element)
if extrusion.Position:
position = Matrix(ifcopenshell.util.placement.get_axis2placement(extrusion.Position).tolist())
position.translation *= self.unit_scale
# Restore the position to before it was changed by the offset and x_angle
rot_matrix = Matrix.Rotation(existing_x_angle, 4, "X")
offset = Vector((0.0, 0.0, -layer_params["offset"]))
rot_offset = offset @ rot_matrix
tranlation_matrix = Matrix.Translation(rot_offset)
position = position @ tranlation_matrix
# Restore Object rotation to zero
local_rot_mat = obj.rotation_euler.to_matrix()
rot_mat = Matrix.Rotation(-existing_x_angle, 4, "X")
new_rot_mat = local_rot_mat.to_4x4() @ rot_mat
new_rot_euler = new_rot_mat.to_euler()
obj.rotation_euler = new_rot_euler
else:
position = Matrix()
tool.Model.import_profile(extrusion.SweptArea, obj=obj, position=position)
tool.Model.import_profile(extrusion.SweptArea, obj=obj, position=position, x_angle=existing_x_angle)
bpy.ops.object.mode_set(mode="EDIT")
ProfileDecorator.install(context, exit_edit_mode_callback=lambda: disable_editing_extrusion_profile(context))
@@ -678,13 +695,30 @@ class EditExtrusionProfile(bpy.types.Operator, tool.Ifc.Operator):
body = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
body = ifcopenshell.util.representation.resolve_representation(body)
extrusion = tool.Model.get_extrusion(body)
existing_x_angle = tool.Model.get_existing_x_angle(extrusion)
layer_params = tool.Model.get_material_layer_parameters(element)
if extrusion.Position:
position = Matrix(ifcopenshell.util.placement.get_axis2placement(extrusion.Position).tolist())
position.translation *= self.unit_scale
# Restore the position to after it was changed by the offset and x_angle
rot_matrix = Matrix.Rotation(existing_x_angle, 4, "X")
offset = Vector((0.0, 0.0, -layer_params["offset"]))
rot_offset = offset @ rot_matrix
tranlation_matrix = Matrix.Translation(rot_offset)
position = position @ tranlation_matrix
# Restore Object rotation to x_angle
local_rot_mat = obj.rotation_euler.to_matrix()
rot_mat = Matrix.Rotation(existing_x_angle, 4, "X")
new_rot_mat = local_rot_mat.to_4x4() @ rot_mat
new_rot_euler = new_rot_mat.to_euler()
obj.rotation_euler = new_rot_euler
else:
position = Matrix()
profile = tool.Model.export_profile(obj, position=position)
profile = tool.Model.export_profile(obj, position=position, x_angle=existing_x_angle)
if not profile:
+12 -7
View File
@@ -36,7 +36,7 @@ import bonsai.core.geometry
import bonsai.core.tool
import bonsai.tool as tool
import bonsai.core.geometry as geometry
from math import atan, degrees, radians
from math import atan, cos, degrees, radians
from mathutils import Matrix, Vector
from copy import deepcopy
from functools import partial
@@ -139,13 +139,13 @@ class Model(bonsai.core.tool.Model):
@classmethod
def export_profile(
cls, obj: bpy.types.Object, position: Optional[Matrix] = None
cls, obj: bpy.types.Object, position: Optional[Matrix] = None, x_angle: Optional[float] = None
) -> ifcopenshell.entity_instance | None:
"""Returns `None` in case if profile was invalid."""
if position is None:
position = Matrix()
result = cls.auto_detect_profiles(obj, obj.data, position)
result = cls.auto_detect_profiles(obj, obj.data, position, x_angle)
if isinstance(result, dict) and result["profile_def"]:
return tool.Ifc.get().add(result["profile_def"])
@@ -286,6 +286,7 @@ class Model(bonsai.core.tool.Model):
profile: ifcopenshell.entity_instance,
obj: Optional[bpy.types.Object] = None,
position: Optional[Matrix] = None,
x_angle: Optional[float] = None,
) -> Union[bpy.types.Object, None]:
"""Creates new profile mesh and assigns it to `obj`,
if `obj` is `None` then new "Profile" object will be created.
@@ -305,10 +306,10 @@ class Model(bonsai.core.tool.Model):
profiles = profile.Profiles if profile.is_a("IfcCompositeProfileDef") else [profile]
for profile in profiles:
if profile.is_a("IfcArbitraryClosedProfileDef"):
cls.convert_curve_to_mesh(obj, position, profile.OuterCurve)
cls.convert_curve_to_mesh(obj, position, profile.OuterCurve, x_angle=x_angle)
if profile.is_a("IfcArbitraryProfileDefWithVoids"):
for inner_curve in profile.InnerCurves:
cls.convert_curve_to_mesh(obj, position, inner_curve)
cls.convert_curve_to_mesh(obj, position, inner_curve, x_angle=x_angle)
elif profile.is_a() == "IfcRectangleProfileDef":
cls.import_rectangle(obj, position, profile)
elif profile.is_a() == "IfcAnnotationFillArea":
@@ -423,7 +424,7 @@ class Model(bonsai.core.tool.Model):
@classmethod
def convert_curve_to_mesh(
cls, obj: bpy.types.Object, position: Matrix, curve: ifcopenshell.entity_instance
cls, obj: bpy.types.Object, position: Matrix, curve: ifcopenshell.entity_instance, x_angle: Optional[float] = None,
) -> None:
offset = len(cls.vertices)
@@ -444,6 +445,8 @@ class Model(bonsai.core.tool.Model):
elif curve.is_a("IfcIndexedPolyCurve"):
for local_point in curve.Points.CoordList:
global_point = position @ Vector(cls.convert_unit_to_si(local_point)).to_3d()
if x_angle:
global_point = Vector((global_point[0], global_point[1] * cos(x_angle), global_point[2]))
cls.vertices.append(global_point)
if curve.Segments:
for segment in curve.Segments:
@@ -1617,7 +1620,7 @@ class Model(bonsai.core.tool.Model):
@classmethod
def auto_detect_profiles(
cls, obj: bpy.types.Object, mesh: bpy.types.Mesh, position: Matrix | None = None
cls, obj: bpy.types.Object, mesh: bpy.types.Mesh, position: Matrix | None = None, x_angle: Optional[float] = None,
) -> Union[tuple, dict]:
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
@@ -1785,6 +1788,8 @@ class Model(bonsai.core.tool.Model):
curves.append(tmp.createIfcPolyline(points))
else: # Pure straight polyline, no segments required
coord_list = [list(((position_i @ v.co) / unit_scale).to_2d()) for v in loop_verts]
if x_angle:
coord_list = [(c[0], c[1] / cos(x_angle)**2) for c in coord_list]
if is_closed:
coord_list.append(coord_list[0])
points = tmp.createIfcCartesianPointList2D(coord_list)