mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-26 02:07:36 +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.geometry
|
||||||
import bonsai.core.root
|
import bonsai.core.root
|
||||||
import bonsai.tool as tool
|
import bonsai.tool as tool
|
||||||
|
from math import cos, radians
|
||||||
from mathutils import Vector, Matrix
|
from mathutils import Vector, Matrix
|
||||||
from bonsai.bim.module.geometry.helper import Helper
|
from bonsai.bim.module.geometry.helper import Helper
|
||||||
from bonsai.bim.module.model.decorator import ProfileDecorator, PolylineDecorator, ProductDecorator
|
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
|
matrix_world.translation.z = self.container_obj.location.z
|
||||||
else:
|
else:
|
||||||
matrix_world.translation.z
|
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()
|
bpy.context.view_layer.update()
|
||||||
|
|
||||||
element = bonsai.core.root.assign_class(
|
element = bonsai.core.root.assign_class(
|
||||||
@@ -305,13 +306,15 @@ class DumbSlabPlaner:
|
|||||||
extrusion = tool.Model.get_extrusion(representation)
|
extrusion = tool.Model.get_extrusion(representation)
|
||||||
if extrusion:
|
if extrusion:
|
||||||
x, y, z = extrusion.ExtrudedDirection.DirectionRatios
|
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 = layer_params["offset"]
|
||||||
offset_vector = Vector((0.0, 0.0, offset / self.unit_scale))
|
offset_vector = Vector((0.0, 0.0, offset / self.unit_scale))
|
||||||
if layer_params["direction_sense"] == "POSITIVE":
|
if layer_params["direction_sense"] == "POSITIVE":
|
||||||
y = abs(y)
|
y = abs(y) if existing_x_angle > 0 else -abs(y)
|
||||||
z = abs(z)
|
z = abs(z)
|
||||||
if layer_params["direction_sense"] == "NEGATIVE":
|
elif layer_params["direction_sense"] == "NEGATIVE":
|
||||||
y = -abs(y)
|
y = -abs(y) if existing_x_angle > 0 else abs(y)
|
||||||
z = -abs(z)
|
z = -abs(z)
|
||||||
offset_vector = -offset_vector
|
offset_vector = -offset_vector
|
||||||
extrusion.ExtrudedDirection.DirectionRatios = (x, y, z)
|
extrusion.ExtrudedDirection.DirectionRatios = (x, y, z)
|
||||||
@@ -319,8 +322,12 @@ class DumbSlabPlaner:
|
|||||||
|
|
||||||
if offset != 0.0 and not extrusion.Position:
|
if offset != 0.0 and not extrusion.Position:
|
||||||
tool.Model.add_extrusion_position(extrusion, offset)
|
tool.Model.add_extrusion_position(extrusion, offset)
|
||||||
|
|
||||||
|
# Update the extrusion's location based on its current rotation angle and offset
|
||||||
if extrusion.Position:
|
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:
|
else:
|
||||||
@@ -373,6 +380,7 @@ class DumbSlabPlaner:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class EnableEditingSketchExtrusionProfile(bpy.types.Operator, tool.Ifc.Operator):
|
class EnableEditingSketchExtrusionProfile(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.enable_editing_sketch_extrusion_profile"
|
bl_idname = "bim.enable_editing_sketch_extrusion_profile"
|
||||||
bl_label = "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.core.model as core
|
||||||
import bonsai.tool as tool
|
import bonsai.tool as tool
|
||||||
from bonsai.bim.ifc import IfcStore
|
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 mathutils import Vector, Matrix
|
||||||
from bonsai.bim.module.model.opening import FilledOpeningGenerator
|
from bonsai.bim.module.model.opening import FilledOpeningGenerator
|
||||||
from bonsai.bim.module.model.decorator import PolylineDecorator, ProductDecorator
|
from bonsai.bim.module.model.decorator import PolylineDecorator, ProductDecorator
|
||||||
@@ -235,13 +235,43 @@ class ChangeExtrusionXAngle(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
if not extrusion:
|
if not extrusion:
|
||||||
return
|
return
|
||||||
x, y, z = extrusion.ExtrudedDirection.DirectionRatios
|
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))
|
perpendicular_depth = extrusion.Depth / (1 / cos(existing_x_angle))
|
||||||
extrusion.Depth = perpendicular_depth * (1 / cos(x_angle))
|
extrusion.Depth = perpendicular_depth * (1 / cos(x_angle))
|
||||||
extrusion.ExtrudedDirection.DirectionRatios = (0.0, sin(x_angle), cos(x_angle))
|
extrusion.ExtrudedDirection.DirectionRatios = (0.0, sin(x_angle), cos(x_angle))
|
||||||
if tool.Model.get_usage_type(element) == "LAYER2":
|
if tool.Model.get_usage_type(element) == "LAYER2":
|
||||||
layer2_objs.append(obj)
|
layer2_objs.append(obj)
|
||||||
else:
|
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(
|
bonsai.core.geometry.switch_representation(
|
||||||
tool.Ifc,
|
tool.Ifc,
|
||||||
tool.Geometry,
|
tool.Geometry,
|
||||||
@@ -252,11 +282,13 @@ class ChangeExtrusionXAngle(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
should_sync_changes_first=False,
|
should_sync_changes_first=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
euler = obj.matrix_world.to_euler()
|
# Object rotation
|
||||||
euler.x = x_angle
|
local_rot_mat = obj.rotation_euler.to_matrix()
|
||||||
new_matrix = euler.to_matrix().to_4x4()
|
rot_mat = mathutils.Matrix.Rotation(x_angle - existing_x_angle, 4, 'X')
|
||||||
new_matrix.translation = obj.matrix_world.translation
|
new_rot_mat = local_rot_mat.to_4x4() @ rot_mat
|
||||||
obj.matrix_world = new_matrix
|
new_rot_euler = new_rot_mat.to_euler()
|
||||||
|
obj.rotation_euler = new_rot_euler
|
||||||
|
|
||||||
if layer2_objs:
|
if layer2_objs:
|
||||||
DumbWallRecalculator().recalculate(layer2_objs)
|
DumbWallRecalculator().recalculate(layer2_objs)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|||||||
@@ -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
|
from math import atan, 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
|
||||||
@@ -2057,3 +2057,18 @@ class Model(bonsai.core.tool.Model):
|
|||||||
|
|
||||||
extrusion.Position = position
|
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(
|
extrusion_direction = self.file.createIfcDirection(
|
||||||
(0.0, sin(self.settings["x_angle"]), cos(self.settings["x_angle"]))
|
(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:
|
else:
|
||||||
extrusion_direction = self.file.createIfcDirection((0.0, 0.0, 1.0))
|
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
|
position = None
|
||||||
# default position for IFC2X3 where .Position is not optional
|
# default position for IFC2X3 where .Position is not optional
|
||||||
|
|||||||
Reference in New Issue
Block a user