mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-28 19:27:10 +00:00
Make slab's editing profile to horizontal orientation when x_angle is present.
This commit is contained in:
@@ -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.get_representation(element, "Model", "Body", "MODEL_VIEW")
|
||||||
body = ifcopenshell.util.representation.resolve_representation(body)
|
body = ifcopenshell.util.representation.resolve_representation(body)
|
||||||
extrusion = tool.Model.get_extrusion(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:
|
if extrusion.Position:
|
||||||
position = Matrix(ifcopenshell.util.placement.get_axis2placement(extrusion.Position).tolist())
|
position = Matrix(ifcopenshell.util.placement.get_axis2placement(extrusion.Position).tolist())
|
||||||
position.translation *= self.unit_scale
|
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:
|
else:
|
||||||
position = Matrix()
|
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")
|
bpy.ops.object.mode_set(mode="EDIT")
|
||||||
ProfileDecorator.install(context, exit_edit_mode_callback=lambda: disable_editing_extrusion_profile(context))
|
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.get_representation(element, "Model", "Body", "MODEL_VIEW")
|
||||||
body = ifcopenshell.util.representation.resolve_representation(body)
|
body = ifcopenshell.util.representation.resolve_representation(body)
|
||||||
extrusion = tool.Model.get_extrusion(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:
|
if extrusion.Position:
|
||||||
position = Matrix(ifcopenshell.util.placement.get_axis2placement(extrusion.Position).tolist())
|
position = Matrix(ifcopenshell.util.placement.get_axis2placement(extrusion.Position).tolist())
|
||||||
position.translation *= self.unit_scale
|
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:
|
else:
|
||||||
position = Matrix()
|
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:
|
if not profile:
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ import bonsai.core.geometry
|
|||||||
import bonsai.core.tool
|
import bonsai.core.tool
|
||||||
import bonsai.tool as tool
|
import bonsai.tool as tool
|
||||||
import bonsai.core.geometry as geometry
|
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 mathutils import Matrix, Vector
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from functools import partial
|
from functools import partial
|
||||||
@@ -139,13 +139,13 @@ class Model(bonsai.core.tool.Model):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def export_profile(
|
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:
|
) -> ifcopenshell.entity_instance | None:
|
||||||
"""Returns `None` in case if profile was invalid."""
|
"""Returns `None` in case if profile was invalid."""
|
||||||
if position is None:
|
if position is None:
|
||||||
position = Matrix()
|
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"]:
|
if isinstance(result, dict) and result["profile_def"]:
|
||||||
return tool.Ifc.get().add(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,
|
profile: ifcopenshell.entity_instance,
|
||||||
obj: Optional[bpy.types.Object] = None,
|
obj: Optional[bpy.types.Object] = None,
|
||||||
position: Optional[Matrix] = None,
|
position: Optional[Matrix] = None,
|
||||||
|
x_angle: Optional[float] = None,
|
||||||
) -> Union[bpy.types.Object, None]:
|
) -> Union[bpy.types.Object, None]:
|
||||||
"""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.
|
||||||
@@ -305,10 +306,10 @@ class Model(bonsai.core.tool.Model):
|
|||||||
profiles = profile.Profiles if profile.is_a("IfcCompositeProfileDef") else [profile]
|
profiles = profile.Profiles if profile.is_a("IfcCompositeProfileDef") else [profile]
|
||||||
for profile in profiles:
|
for profile in profiles:
|
||||||
if profile.is_a("IfcArbitraryClosedProfileDef"):
|
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"):
|
if profile.is_a("IfcArbitraryProfileDefWithVoids"):
|
||||||
for inner_curve in profile.InnerCurves:
|
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":
|
elif profile.is_a() == "IfcRectangleProfileDef":
|
||||||
cls.import_rectangle(obj, position, profile)
|
cls.import_rectangle(obj, position, profile)
|
||||||
elif profile.is_a() == "IfcAnnotationFillArea":
|
elif profile.is_a() == "IfcAnnotationFillArea":
|
||||||
@@ -423,7 +424,7 @@ class Model(bonsai.core.tool.Model):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def convert_curve_to_mesh(
|
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:
|
) -> None:
|
||||||
offset = len(cls.vertices)
|
offset = len(cls.vertices)
|
||||||
|
|
||||||
@@ -444,6 +445,8 @@ class Model(bonsai.core.tool.Model):
|
|||||||
elif curve.is_a("IfcIndexedPolyCurve"):
|
elif curve.is_a("IfcIndexedPolyCurve"):
|
||||||
for local_point in curve.Points.CoordList:
|
for local_point in curve.Points.CoordList:
|
||||||
global_point = position @ Vector(cls.convert_unit_to_si(local_point)).to_3d()
|
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)
|
cls.vertices.append(global_point)
|
||||||
if curve.Segments:
|
if curve.Segments:
|
||||||
for segment in curve.Segments:
|
for segment in curve.Segments:
|
||||||
@@ -1617,7 +1620,7 @@ class Model(bonsai.core.tool.Model):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def auto_detect_profiles(
|
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]:
|
) -> Union[tuple, dict]:
|
||||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
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))
|
curves.append(tmp.createIfcPolyline(points))
|
||||||
else: # Pure straight polyline, no segments required
|
else: # Pure straight polyline, no segments required
|
||||||
coord_list = [list(((position_i @ v.co) / unit_scale).to_2d()) for v in loop_verts]
|
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:
|
if is_closed:
|
||||||
coord_list.append(coord_list[0])
|
coord_list.append(coord_list[0])
|
||||||
points = tmp.createIfcCartesianPointList2D(coord_list)
|
points = tmp.createIfcCartesianPointList2D(coord_list)
|
||||||
|
|||||||
Reference in New Issue
Block a user