mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-22 14:38:05 +00:00
Add basic support for sloped walls, sloping along the local X axis
This commit is contained in:
@@ -31,6 +31,7 @@ classes = (
|
|||||||
workspace.Hotkey,
|
workspace.Hotkey,
|
||||||
wall.AlignWall,
|
wall.AlignWall,
|
||||||
wall.ChangeExtrusionDepth,
|
wall.ChangeExtrusionDepth,
|
||||||
|
wall.ChangeExtrusionXAngle,
|
||||||
wall.ChangeLayerLength,
|
wall.ChangeLayerLength,
|
||||||
wall.FlipWall,
|
wall.FlipWall,
|
||||||
wall.JoinWall,
|
wall.JoinWall,
|
||||||
|
|||||||
@@ -229,6 +229,7 @@ class BIMModelProperties(PropertyGroup):
|
|||||||
y: bpy.props.FloatProperty(name="Y", default=0.5)
|
y: bpy.props.FloatProperty(name="Y", default=0.5)
|
||||||
z: bpy.props.FloatProperty(name="Z", default=0.5)
|
z: bpy.props.FloatProperty(name="Z", default=0.5)
|
||||||
rl: bpy.props.FloatProperty(name="RL", default=1)
|
rl: bpy.props.FloatProperty(name="RL", default=1)
|
||||||
|
x_angle: bpy.props.FloatProperty(name="X Angle", default=0)
|
||||||
type_page: bpy.props.IntProperty(name="Type Page", default=1, update=update_type_page)
|
type_page: bpy.props.IntProperty(name="Type Page", default=1, update=update_type_page)
|
||||||
type_template: bpy.props.EnumProperty(
|
type_template: bpy.props.EnumProperty(
|
||||||
items=(
|
items=(
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ import blenderbim.tool as tool
|
|||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from ifcopenshell.api.pset.data import Data as PsetData
|
from ifcopenshell.api.pset.data import Data as PsetData
|
||||||
from ifcopenshell.api.material.data import Data as MaterialData
|
from ifcopenshell.api.material.data import Data as MaterialData
|
||||||
from math import pi, degrees
|
from math import pi, sin, cos, degrees, radians
|
||||||
from mathutils import Vector, Matrix
|
from mathutils import Vector, Matrix
|
||||||
|
|
||||||
|
|
||||||
@@ -243,6 +243,37 @@ class ChangeExtrusionDepth(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
class ChangeExtrusionXAngle(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
|
bl_idname = "bim.change_extrusion_x_angle"
|
||||||
|
bl_label = "Change Extrusion X Angle"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
x_angle: bpy.props.FloatProperty()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
return context.selected_objects
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
|
wall_objs = []
|
||||||
|
x_angle = radians(self.x_angle)
|
||||||
|
for obj in context.selected_objects:
|
||||||
|
element = tool.Ifc.get_entity(obj)
|
||||||
|
if not element:
|
||||||
|
return
|
||||||
|
representation = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
|
||||||
|
if not representation:
|
||||||
|
return
|
||||||
|
extrusion = tool.Model.get_extrusion(representation)
|
||||||
|
if not extrusion:
|
||||||
|
return
|
||||||
|
extrusion.ExtrudedDirection.DirectionRatios = (0.0, sin(x_angle), cos(x_angle))
|
||||||
|
if element.is_a("IfcWall"):
|
||||||
|
wall_objs.append(obj)
|
||||||
|
if wall_objs:
|
||||||
|
DumbWallRecalculator().recalculate(wall_objs)
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class ChangeLayerLength(bpy.types.Operator, tool.Ifc.Operator):
|
class ChangeLayerLength(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.change_layer_length"
|
bl_idname = "bim.change_layer_length"
|
||||||
bl_label = "Change Layer Length"
|
bl_label = "Change Layer Length"
|
||||||
@@ -419,6 +450,7 @@ class DumbWallGenerator:
|
|||||||
self.length = props.length * self.unit_scale
|
self.length = props.length * self.unit_scale
|
||||||
self.rotation = 0.0
|
self.rotation = 0.0
|
||||||
self.location = Vector((0, 0, 0))
|
self.location = Vector((0, 0, 0))
|
||||||
|
self.x_angle = 0 if tool.Cad.is_x(props.x_angle, 0, tolerance=0.001) else radians(props.x_angle)
|
||||||
|
|
||||||
if self.has_sketch():
|
if self.has_sketch():
|
||||||
return # For now
|
return # For now
|
||||||
@@ -571,6 +603,7 @@ class DumbWallGenerator:
|
|||||||
offset=self.layers["offset"],
|
offset=self.layers["offset"],
|
||||||
length=self.length,
|
length=self.length,
|
||||||
height=self.height,
|
height=self.height,
|
||||||
|
x_angle=self.x_angle,
|
||||||
)
|
)
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"geometry.assign_representation", tool.Ifc.get(), product=element, representation=representation
|
"geometry.assign_representation", tool.Ifc.get(), product=element, representation=representation
|
||||||
@@ -993,7 +1026,9 @@ class DumbWallJoiner:
|
|||||||
axis = body = tool.Model.get_wall_axis(obj)["reference"]
|
axis = body = tool.Model.get_wall_axis(obj)["reference"]
|
||||||
self.axis = copy.deepcopy(axis)
|
self.axis = copy.deepcopy(axis)
|
||||||
self.body = copy.deepcopy(body)
|
self.body = copy.deepcopy(body)
|
||||||
height = self.get_height(tool.Ifc.get().by_id(obj.data.BIMMeshProperties.ifc_definition_id))
|
extrusion_data = self.get_extrusion_data(tool.Ifc.get().by_id(obj.data.BIMMeshProperties.ifc_definition_id))
|
||||||
|
height = extrusion_data["height"]
|
||||||
|
x_angle = extrusion_data["x_angle"]
|
||||||
self.clippings = []
|
self.clippings = []
|
||||||
layers = tool.Model.get_material_layer_parameters(element)
|
layers = tool.Model.get_material_layer_parameters(element)
|
||||||
|
|
||||||
@@ -1045,6 +1080,7 @@ class DumbWallJoiner:
|
|||||||
context=self.body_context,
|
context=self.body_context,
|
||||||
length=length,
|
length=length,
|
||||||
height=height,
|
height=height,
|
||||||
|
x_angle=x_angle,
|
||||||
offset=layers["offset"],
|
offset=layers["offset"],
|
||||||
thickness=layers["thickness"],
|
thickness=layers["thickness"],
|
||||||
clippings=self.clippings,
|
clippings=self.clippings,
|
||||||
@@ -1106,18 +1142,21 @@ class DumbWallJoiner:
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_height(self, representation):
|
def get_extrusion_data(self, representation):
|
||||||
height = 3.0
|
results = {"height": 3.0, "x_angle": 0}
|
||||||
item = representation.Items[0]
|
item = representation.Items[0]
|
||||||
while True:
|
while True:
|
||||||
if item.is_a("IfcExtrudedAreaSolid"):
|
if item.is_a("IfcExtrudedAreaSolid"):
|
||||||
height = item.Depth * self.unit_scale
|
results["height"] = item.Depth * self.unit_scale
|
||||||
|
x, y, z = item.ExtrudedDirection.DirectionRatios
|
||||||
|
if not tool.Cad.is_x(x, 0) or not tool.Cad.is_x(y, 0) or not tool.Cad.is_x(z, 1):
|
||||||
|
results["x_angle"] = Vector((0, 1)).angle(Vector((y, z)))
|
||||||
break
|
break
|
||||||
elif item.is_a("IfcBooleanClippingResult"):
|
elif item.is_a("IfcBooleanClippingResult"):
|
||||||
item = item.FirstOperand
|
item = item.FirstOperand
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
return height
|
return results
|
||||||
|
|
||||||
def join(self, wall1, wall2, connection1, connection2, is_relating=True, description="BUTT"):
|
def join(self, wall1, wall2, connection1, connection2, is_relating=True, description="BUTT"):
|
||||||
element1 = tool.Ifc.get_entity(wall1)
|
element1 = tool.Ifc.get_entity(wall1)
|
||||||
|
|||||||
@@ -101,6 +101,9 @@ class BimToolUI:
|
|||||||
|
|
||||||
row = cls.layout.row(align=True)
|
row = cls.layout.row(align=True)
|
||||||
row.prop(data=cls.props, property="length", text="Length")
|
row.prop(data=cls.props, property="length", text="Length")
|
||||||
|
|
||||||
|
row = cls.layout.row(align=True)
|
||||||
|
row.prop(data=cls.props, property="x_angle", text="X Angle")
|
||||||
elif cls.props.ifc_class in ("IfcColumnType", "IfcBeamType", "IfcMemberType"):
|
elif cls.props.ifc_class in ("IfcColumnType", "IfcBeamType", "IfcMemberType"):
|
||||||
row = cls.layout.row(align=True)
|
row = cls.layout.row(align=True)
|
||||||
row.prop(data=cls.props, property="cardinal_point", text="Axis")
|
row.prop(data=cls.props, property="cardinal_point", text="Axis")
|
||||||
@@ -125,6 +128,11 @@ class BimToolUI:
|
|||||||
op = row.operator("bim.change_layer_length", icon="FILE_REFRESH", text="")
|
op = row.operator("bim.change_layer_length", icon="FILE_REFRESH", text="")
|
||||||
op.length = cls.props.length
|
op.length = cls.props.length
|
||||||
|
|
||||||
|
row = cls.layout.row(align=True)
|
||||||
|
row.prop(data=cls.props, property="x_angle", text="X Angle")
|
||||||
|
op = row.operator("bim.change_extrusion_x_angle", icon="FILE_REFRESH", text="")
|
||||||
|
op.x_angle = cls.props.x_angle
|
||||||
|
|
||||||
row = cls.layout.row(align=True)
|
row = cls.layout.row(align=True)
|
||||||
row.label(text="", icon="EVENT_SHIFT")
|
row.label(text="", icon="EVENT_SHIFT")
|
||||||
row.label(text="", icon="EVENT_E")
|
row.label(text="", icon="EVENT_E")
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from math import sin, cos
|
||||||
import ifcopenshell.util.unit
|
import ifcopenshell.util.unit
|
||||||
|
|
||||||
|
|
||||||
@@ -28,10 +29,12 @@ class Usecase:
|
|||||||
"height": 3.0,
|
"height": 3.0,
|
||||||
"offset": 0.0,
|
"offset": 0.0,
|
||||||
"thickness": 0.2,
|
"thickness": 0.2,
|
||||||
|
# Sloped walls along the wall's X axis, provided in radians
|
||||||
|
"x_angle": 0,
|
||||||
# Planes are defined as a matrix. The XY plane is the clipping boundary and +Z is removed.
|
# Planes are defined as a matrix. The XY plane is the clipping boundary and +Z is removed.
|
||||||
# [{"type": "IfcBooleanClippingResult", "operand_type": "IfcHalfSpaceSolid", "matrix": [...]}, {...}]
|
# [{"type": "IfcBooleanClippingResult", "operand_type": "IfcHalfSpaceSolid", "matrix": [...]}, {...}]
|
||||||
"clippings": [], # A list of planes that define clipping half space solids
|
"clippings": [], # A list of planes that define clipping half space solids
|
||||||
"booleans": [], # Any existing IfcBooleanResults
|
"booleans": [], # Any existing IfcBooleanResults
|
||||||
}
|
}
|
||||||
for key, value in settings.items():
|
for key, value in settings.items():
|
||||||
self.settings[key] = value
|
self.settings[key] = value
|
||||||
@@ -59,6 +62,12 @@ class Usecase:
|
|||||||
curve = self.file.createIfcPolyline([self.file.createIfcCartesianPoint(p) for p in points])
|
curve = self.file.createIfcPolyline([self.file.createIfcCartesianPoint(p) for p in points])
|
||||||
else:
|
else:
|
||||||
curve = self.file.createIfcIndexedPolyCurve(self.file.createIfcCartesianPointList2D(points), None, False)
|
curve = self.file.createIfcIndexedPolyCurve(self.file.createIfcCartesianPointList2D(points), None, False)
|
||||||
|
if self.settings["x_angle"]:
|
||||||
|
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))
|
||||||
extrusion = self.file.createIfcExtrudedAreaSolid(
|
extrusion = self.file.createIfcExtrudedAreaSolid(
|
||||||
self.file.createIfcArbitraryClosedProfileDef("AREA", None, curve),
|
self.file.createIfcArbitraryClosedProfileDef("AREA", None, curve),
|
||||||
self.file.createIfcAxis2Placement3D(
|
self.file.createIfcAxis2Placement3D(
|
||||||
@@ -66,7 +75,7 @@ class Usecase:
|
|||||||
self.file.createIfcDirection((0.0, 0.0, 1.0)),
|
self.file.createIfcDirection((0.0, 0.0, 1.0)),
|
||||||
self.file.createIfcDirection((1.0, 0.0, 0.0)),
|
self.file.createIfcDirection((1.0, 0.0, 0.0)),
|
||||||
),
|
),
|
||||||
self.file.createIfcDirection((0.0, 0.0, 1.0)),
|
extrusion_direction,
|
||||||
self.convert_si_to_unit(self.settings["height"]),
|
self.convert_si_to_unit(self.settings["height"]),
|
||||||
)
|
)
|
||||||
if self.settings["booleans"]:
|
if self.settings["booleans"]:
|
||||||
|
|||||||
Reference in New Issue
Block a user