Add support for direction sense and offset in slabs with x_angle

This commit is contained in:
Bruno Perdigão
2025-01-20 19:00:44 -03:00
parent 372654267c
commit c72f17068c
4 changed files with 74 additions and 13 deletions
+13 -5
View File
@@ -30,6 +30,7 @@ import bonsai.core.type
import bonsai.core.geometry
import bonsai.core.root
import bonsai.tool as tool
from math import cos, radians
from mathutils import Vector, Matrix
from bonsai.bim.module.geometry.helper import Helper
from bonsai.bim.module.model.decorator import ProfileDecorator, PolylineDecorator, ProductDecorator
@@ -134,7 +135,7 @@ class DumbSlabGenerator:
matrix_world.translation.z = self.container_obj.location.z
else:
matrix_world.translation.z
obj.matrix_world = Matrix.Rotation(self.x_angle, 4, "X") @ matrix_world
obj.matrix_world = matrix_world @ Matrix.Rotation(self.x_angle, 4, "X")
bpy.context.view_layer.update()
element = bonsai.core.root.assign_class(
@@ -305,13 +306,15 @@ class DumbSlabPlaner:
extrusion = tool.Model.get_extrusion(representation)
if extrusion:
x, y, z = extrusion.ExtrudedDirection.DirectionRatios
existing_x_angle = tool.Model.get_existing_x_angle(extrusion)
perpendicular_depth = thickness * (1 / cos(existing_x_angle))
offset = layer_params["offset"]
offset_vector = Vector((0.0, 0.0, offset / self.unit_scale))
if layer_params["direction_sense"] == "POSITIVE":
y = abs(y)
y = abs(y) if existing_x_angle > 0 else -abs(y)
z = abs(z)
if layer_params["direction_sense"] == "NEGATIVE":
y = -abs(y)
elif layer_params["direction_sense"] == "NEGATIVE":
y = -abs(y) if existing_x_angle > 0 else abs(y)
z = -abs(z)
offset_vector = -offset_vector
extrusion.ExtrudedDirection.DirectionRatios = (x, y, z)
@@ -319,8 +322,12 @@ class DumbSlabPlaner:
if offset != 0.0 and not extrusion.Position:
tool.Model.add_extrusion_position(extrusion, offset)
# Update the extrusion's location based on its current rotation angle and offset
if extrusion.Position:
extrusion.Position.Location.Coordinates = tuple(offset_vector)
rot_matrix = Matrix.Rotation(existing_x_angle, 4, "X")
rot_offset = offset_vector @ rot_matrix
extrusion.Position.Location.Coordinates = tuple(rot_offset)
else:
@@ -373,6 +380,7 @@ class DumbSlabPlaner:
)
class EnableEditingSketchExtrusionProfile(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.enable_editing_sketch_extrusion_profile"
bl_label = "Enable Editing Sketch Extrusion Profile"
+39 -7
View File
@@ -36,7 +36,7 @@ import bonsai.core.geometry
import bonsai.core.model as core
import bonsai.tool as tool
from bonsai.bim.ifc import IfcStore
from math import pi, sin, cos, degrees
from math import pi, sin, cos, degrees, radians
from mathutils import Vector, Matrix
from bonsai.bim.module.model.opening import FilledOpeningGenerator
from bonsai.bim.module.model.decorator import PolylineDecorator, ProductDecorator
@@ -235,13 +235,43 @@ class ChangeExtrusionXAngle(bpy.types.Operator, tool.Ifc.Operator):
if not extrusion:
return
x, y, z = extrusion.ExtrudedDirection.DirectionRatios
existing_x_angle = Vector((0, 1)).angle_signed(Vector((y, z)))
existing_x_angle = tool.Model.get_existing_x_angle(extrusion)
perpendicular_depth = extrusion.Depth / (1 / cos(existing_x_angle))
extrusion.Depth = perpendicular_depth * (1 / cos(x_angle))
extrusion.ExtrudedDirection.DirectionRatios = (0.0, sin(x_angle), cos(x_angle))
if tool.Model.get_usage_type(element) == "LAYER2":
layer2_objs.append(obj)
else:
if tool.Model.get_usage_type(element) == "LAYER3":
# Reset the transformation and returns to the original points with 0 degrees
extrusion.SweptArea.OuterCurve.Points.CoordList = [(p[0], p[1] * (cos(existing_x_angle))) for p in extrusion.SweptArea.OuterCurve.Points.CoordList]
# Apply the transformation for the new x_angle
extrusion.SweptArea.OuterCurve.Points.CoordList = [(p[0], p[1] * (1 / cos(x_angle))) for p in extrusion.SweptArea.OuterCurve.Points.CoordList]
# The extrusion direction calculated previously default to the positive direction
# Here we set the extrusion direction to negative it that's the case
x, y, z = extrusion.ExtrudedDirection.DirectionRatios
layer_params = tool.Model.get_material_layer_parameters(element)
offset = layer_params["offset"]
offset_vector = Vector((0.0, 0.0, offset / unit_scale))
if layer_params["direction_sense"] == "NEGATIVE":
y = -abs(y) if x_angle > 0 else abs(y)
z = -abs(z)
offset_vector = -offset_vector
extrusion.ExtrudedDirection.DirectionRatios = (x, y, z)
if offset != 0.0 and not extrusion.Position:
tool.Model.add_extrusion_position(extrusion, offset)
# Update the extrusion's location based on its current rotation angle
if extrusion.Position:
rot_matrix = Matrix.Rotation(x_angle, 4, "X")
rot_offset = offset_vector @ rot_matrix
extrusion.Position.Location.Coordinates = tuple(rot_offset)
bonsai.core.geometry.switch_representation(
tool.Ifc,
tool.Geometry,
@@ -252,11 +282,13 @@ class ChangeExtrusionXAngle(bpy.types.Operator, tool.Ifc.Operator):
should_sync_changes_first=False,
)
euler = obj.matrix_world.to_euler()
euler.x = x_angle
new_matrix = euler.to_matrix().to_4x4()
new_matrix.translation = obj.matrix_world.translation
obj.matrix_world = new_matrix
# Object rotation
local_rot_mat = obj.rotation_euler.to_matrix()
rot_mat = mathutils.Matrix.Rotation(x_angle - 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
if layer2_objs:
DumbWallRecalculator().recalculate(layer2_objs)
return {"FINISHED"}
+16 -1
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
from math import atan, degrees, radians
from mathutils import Matrix, Vector
from copy import deepcopy
from functools import partial
@@ -2057,3 +2057,18 @@ class Model(bonsai.core.tool.Model):
extrusion.Position = position
@classmethod
def get_existing_x_angle(cls, extrusion):
x, y, z = extrusion.ExtrudedDirection.DirectionRatios
# The existing angle result can change when the direction sense in Negative because the DirectionRatios may have negative y and z.
# For instance, a 30 degree angled slab, with negative direction will show as -150 degrees. To prevent that we do the following transformations
existing_x_angle = Vector((0, 1)).angle_signed(Vector((y, z)))
existing_x_angle = (
existing_x_angle + radians(180) if existing_x_angle < -radians(90) else existing_x_angle
)
existing_x_angle = (
existing_x_angle - radians(180) if existing_x_angle > radians(90) else existing_x_angle
)
return existing_x_angle
@@ -93,8 +93,14 @@ class Usecase:
extrusion_direction = self.file.createIfcDirection(
(0.0, sin(self.settings["x_angle"]), cos(self.settings["x_angle"]))
)
if self.settings["direction_sense"] == "NEGATIVE":
extrusion_direction = self.file.createIfcDirection(
(0.0, -sin(self.settings["x_angle"]), -cos(self.settings["x_angle"]))
)
else:
extrusion_direction = self.file.createIfcDirection((0.0, 0.0, 1.0))
if self.settings["direction_sense"] == "NEGATIVE":
extrusion_direction = self.file.createIfcDirection((0.0, 0.0, -1.0))
position = None
# default position for IFC2X3 where .Position is not optional