mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-12 18:43:26 +00:00
Add support for direction sense and offset in slabs with x_angle
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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"}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user