Filled openings now handle offset wall axes

This commit is contained in:
Dion Moult
2022-10-16 10:16:10 +11:00
parent 56a09e51bd
commit 76e6923a3e
3 changed files with 61 additions and 59 deletions
@@ -64,9 +64,10 @@ class AddFilledOpening(bpy.types.Operator, tool.Ifc.Operator):
if not raycast[0]: if not raycast[0]:
return {"FINISHED"} return {"FINISHED"}
axis = [voided_obj.matrix_world @ Vector((0, 0, 0)), voided_obj.matrix_world @ Vector((1, 0, 0))]
# In this prototype, we assume openings are only added to axis-based elements # In this prototype, we assume openings are only added to axis-based elements
layers = tool.Model.get_material_layer_parameters(element)
axis = tool.Model.get_wall_axis(voided_obj, layers=layers)["base"]
new_matrix = voided_obj.matrix_world.copy() new_matrix = voided_obj.matrix_world.copy()
new_matrix.col[3] = tool.Cad.point_on_edge(target, axis).to_4d() new_matrix.col[3] = tool.Cad.point_on_edge(target, axis).to_4d()
if not filling.is_a("IfcDoor"): if not filling.is_a("IfcDoor"):
@@ -404,7 +404,7 @@ class DumbWallGenerator:
def generate(self, link_to_scene=True): def generate(self, link_to_scene=True):
self.file = IfcStore.get_file() self.file = IfcStore.get_file()
self.layers = get_material_layer_parameters(self.relating_type) self.layers = tool.Model.get_material_layer_parameters(self.relating_type)
if not self.layers["thickness"]: if not self.layers["thickness"]:
return return
@@ -698,7 +698,7 @@ class DumbWallJoiner:
ifcopenshell.api.run("geometry.disconnect_path", tool.Ifc.get(), element=element1, connection_type="ATSTART") ifcopenshell.api.run("geometry.disconnect_path", tool.Ifc.get(), element=element1, connection_type="ATSTART")
ifcopenshell.api.run("geometry.disconnect_path", tool.Ifc.get(), element=element1, connection_type="ATEND") ifcopenshell.api.run("geometry.disconnect_path", tool.Ifc.get(), element=element1, connection_type="ATEND")
axis1 = self.get_wall_axis(wall1) axis1 = tool.Model.get_wall_axis(wall1)
axis = copy.deepcopy(axis1["reference"]) axis = copy.deepcopy(axis1["reference"])
body = copy.deepcopy(axis1["reference"]) body = copy.deepcopy(axis1["reference"])
self.recreate_wall(element1, wall1, axis, body) self.recreate_wall(element1, wall1, axis, body)
@@ -707,7 +707,7 @@ class DumbWallJoiner:
element1 = tool.Ifc.get_entity(wall1) element1 = tool.Ifc.get_entity(wall1)
if not element1: if not element1:
return return
axis1 = self.get_wall_axis(wall1) axis1 = tool.Model.get_wall_axis(wall1)
axis2 = copy.deepcopy(axis1) axis2 = copy.deepcopy(axis1)
intersect, connection = mathutils.geometry.intersect_point_line(target.to_2d(), *axis1["reference"]) intersect, connection = mathutils.geometry.intersect_point_line(target.to_2d(), *axis1["reference"])
if connection < 0 or connection > 1 or tool.Cad.is_x(connection, (0, 1)): if connection < 0 or connection > 1 or tool.Cad.is_x(connection, (0, 1)):
@@ -738,7 +738,7 @@ class DumbWallJoiner:
if rel.RelatedConnectionType in ["ATSTART", "ATEND"]: if rel.RelatedConnectionType in ["ATSTART", "ATEND"]:
rel.RelatedConnectionType = "ATSTART" if rel.RelatedConnectionType == "ATEND" else "ATEND" rel.RelatedConnectionType = "ATSTART" if rel.RelatedConnectionType == "ATEND" else "ATEND"
axis1 = self.get_wall_axis(wall1) axis1 = tool.Model.get_wall_axis(wall1)
axis1["reference"][0], axis1["reference"][1] = axis1["reference"][1], axis1["reference"][0] axis1["reference"][0], axis1["reference"][1] = axis1["reference"][1], axis1["reference"][0]
flip_matrix = Matrix.Rotation(pi, 4, "Z") flip_matrix = Matrix.Rotation(pi, 4, "Z")
@@ -751,8 +751,8 @@ class DumbWallJoiner:
def merge(self, wall1, wall2): def merge(self, wall1, wall2):
element1 = tool.Ifc.get_entity(wall1) element1 = tool.Ifc.get_entity(wall1)
element2 = tool.Ifc.get_entity(wall2) element2 = tool.Ifc.get_entity(wall2)
axis1 = self.get_wall_axis(wall1) axis1 = tool.Model.get_wall_axis(wall1)
axis2 = self.get_wall_axis(wall2) axis2 = tool.Model.get_wall_axis(wall2)
angle = tool.Cad.angle_edges(axis1["reference"], axis2["reference"], signed=False, degrees=True) angle = tool.Cad.angle_edges(axis1["reference"], axis2["reference"], signed=False, degrees=True)
if not tool.Cad.is_x(angle, 0, tolerance=0.001): if not tool.Cad.is_x(angle, 0, tolerance=0.001):
@@ -816,8 +816,8 @@ class DumbWallJoiner:
def join_L(self, wall1, wall2): def join_L(self, wall1, wall2):
element1 = tool.Ifc.get_entity(wall1) element1 = tool.Ifc.get_entity(wall1)
element2 = tool.Ifc.get_entity(wall2) element2 = tool.Ifc.get_entity(wall2)
axis1 = self.get_wall_axis(wall1) axis1 = tool.Model.get_wall_axis(wall1)
axis2 = self.get_wall_axis(wall2) axis2 = tool.Model.get_wall_axis(wall2)
intersect = tool.Cad.intersect_edges(axis1["reference"], axis2["reference"]) intersect = tool.Cad.intersect_edges(axis1["reference"], axis2["reference"])
if intersect: if intersect:
intersect, _ = intersect intersect, _ = intersect
@@ -844,7 +844,7 @@ class DumbWallJoiner:
if not element1: if not element1:
return return
axis1 = self.get_wall_axis(wall1) axis1 = tool.Model.get_wall_axis(wall1)
intersect, connection = mathutils.geometry.intersect_point_line(target.to_2d(), *axis1["reference"]) intersect, connection = mathutils.geometry.intersect_point_line(target.to_2d(), *axis1["reference"])
connection = "ATEND" if connection > 0.5 else "ATSTART" connection = "ATEND" if connection > 0.5 else "ATSTART"
@@ -864,7 +864,7 @@ class DumbWallJoiner:
ifcopenshell.api.run("geometry.disconnect_path", tool.Ifc.get(), element=element1, connection_type="ATEND") ifcopenshell.api.run("geometry.disconnect_path", tool.Ifc.get(), element=element1, connection_type="ATEND")
axis1 = self.get_wall_axis(wall1) axis1 = tool.Model.get_wall_axis(wall1)
axis = copy.deepcopy(axis1["reference"]) axis = copy.deepcopy(axis1["reference"])
body = copy.deepcopy(axis1["reference"]) body = copy.deepcopy(axis1["reference"])
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
@@ -877,8 +877,8 @@ class DumbWallJoiner:
def join_T(self, wall1, wall2): def join_T(self, wall1, wall2):
element1 = tool.Ifc.get_entity(wall1) element1 = tool.Ifc.get_entity(wall1)
element2 = tool.Ifc.get_entity(wall2) element2 = tool.Ifc.get_entity(wall2)
axis1 = self.get_wall_axis(wall1) axis1 = tool.Model.get_wall_axis(wall1)
axis2 = self.get_wall_axis(wall2) axis2 = tool.Model.get_wall_axis(wall2)
intersect = tool.Cad.intersect_edges(axis1["reference"], axis2["reference"]) intersect = tool.Cad.intersect_edges(axis1["reference"], axis2["reference"])
if intersect: if intersect:
intersect, _ = intersect intersect, _ = intersect
@@ -901,8 +901,8 @@ class DumbWallJoiner:
def join_V(self, wall1, wall2): def join_V(self, wall1, wall2):
element1 = tool.Ifc.get_entity(wall1) element1 = tool.Ifc.get_entity(wall1)
element2 = tool.Ifc.get_entity(wall2) element2 = tool.Ifc.get_entity(wall2)
axis1 = self.get_wall_axis(wall1) axis1 = tool.Model.get_wall_axis(wall1)
axis2 = self.get_wall_axis(wall2) axis2 = tool.Model.get_wall_axis(wall2)
intersect = tool.Cad.intersect_edges(axis1["reference"], axis2["reference"]) intersect = tool.Cad.intersect_edges(axis1["reference"], axis2["reference"])
if intersect: if intersect:
intersect, _ = intersect intersect, _ = intersect
@@ -926,12 +926,12 @@ class DumbWallJoiner:
def recreate_wall(self, element, obj, axis=None, body=None): def recreate_wall(self, element, obj, axis=None, body=None):
if axis is None or body is None: if axis is None or body is None:
axis = body = self.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)) height = self.get_height(tool.Ifc.get().by_id(obj.data.BIMMeshProperties.ifc_definition_id))
self.clippings = [] self.clippings = []
layers = get_material_layer_parameters(element) layers = tool.Model.get_material_layer_parameters(element)
for rel in element.ConnectedTo: for rel in element.ConnectedTo:
connection = rel.RelatingConnectionType connection = rel.RelatingConnectionType
@@ -1041,28 +1041,6 @@ class DumbWallJoiner:
) )
) )
def get_wall_axis(self, obj, layers=None):
x_values = [v[0] for v in obj.bound_box]
min_x = min(x_values)
max_x = max(x_values)
axes = {}
if layers:
axes = {
"base": [
(obj.matrix_world @ Vector((min_x, layers["offset"], 0.0))).to_2d(),
(obj.matrix_world @ Vector((max_x, layers["offset"], 0.0))).to_2d(),
],
"side": [
(obj.matrix_world @ Vector((min_x, layers["offset"] + layers["thickness"], 0.0))).to_2d(),
(obj.matrix_world @ Vector((max_x, layers["offset"] + layers["thickness"], 0.0))).to_2d(),
],
}
axes["reference"] = [
(obj.matrix_world @ Vector((min_x, 0.0, 0.0))).to_2d(),
(obj.matrix_world @ Vector((max_x, 0.0, 0.0))).to_2d(),
]
return axes
def get_height(self, representation): def get_height(self, representation):
height = 3.0 height = 3.0
item = representation.Items[0] item = representation.Items[0]
@@ -1079,10 +1057,10 @@ class DumbWallJoiner:
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)
element2 = tool.Ifc.get_entity(wall2) element2 = tool.Ifc.get_entity(wall2)
layers1 = get_material_layer_parameters(element1) layers1 = tool.Model.get_material_layer_parameters(element1)
layers2 = get_material_layer_parameters(element2) layers2 = tool.Model.get_material_layer_parameters(element2)
axis1 = self.get_wall_axis(wall1, layers1) axis1 = tool.Model.get_wall_axis(wall1, layers1)
axis2 = self.get_wall_axis(wall2, layers2) axis2 = tool.Model.get_wall_axis(wall2, layers2)
angle = tool.Cad.angle_edges(axis1["reference"], axis2["reference"], signed=True, degrees=True) angle = tool.Cad.angle_edges(axis1["reference"], axis2["reference"], signed=True, degrees=True)
if tool.Cad.is_x(abs(angle), (0, 180), tolerance=0.001): if tool.Cad.is_x(abs(angle), (0, 180), tolerance=0.001):
@@ -1271,17 +1249,3 @@ class DumbWallJoiner:
} }
) )
return True return True
def get_material_layer_parameters(element):
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
offset = 0.0
thickness = 0.0
material = ifcopenshell.util.element.get_material(element)
if material:
if material.is_a("IfcMaterialLayerSetUsage"):
offset = material.OffsetFromReferenceLine * unit_scale
material = material.ForLayerSet
if material.is_a("IfcMaterialLayerSet"):
thickness = sum([l.LayerThickness for l in material.MaterialLayers]) * unit_scale
return {"thickness": thickness, "offset": offset}
+38 -1
View File
@@ -22,7 +22,7 @@ import ifcopenshell.util.placement
import ifcopenshell.util.representation import ifcopenshell.util.representation
import blenderbim.core.tool import blenderbim.core.tool
import blenderbim.tool as tool import blenderbim.tool as tool
from mathutils import Matrix from mathutils import Matrix, Vector
from blenderbim.bim import import_ifc from blenderbim.bim import import_ifc
@@ -86,6 +86,20 @@ class Model(blenderbim.core.tool.Model):
props.openings.remove(i) props.openings.remove(i)
has_deleted_opening = True has_deleted_opening = True
@classmethod
def get_material_layer_parameters(cls, element):
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
offset = 0.0
thickness = 0.0
material = ifcopenshell.util.element.get_material(element)
if material:
if material.is_a("IfcMaterialLayerSetUsage"):
offset = material.OffsetFromReferenceLine * unit_scale
material = material.ForLayerSet
if material.is_a("IfcMaterialLayerSet"):
thickness = sum([l.LayerThickness for l in material.MaterialLayers]) * unit_scale
return {"thickness": thickness, "offset": offset}
@classmethod @classmethod
def get_manual_booleans(cls, element): def get_manual_booleans(cls, element):
body = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW") body = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
@@ -101,3 +115,26 @@ class Model(blenderbim.core.tool.Model):
elif item.is_a("IfcBooleanClippingResult"): elif item.is_a("IfcBooleanClippingResult"):
items.append(item.FirstOperand) items.append(item.FirstOperand)
return booleans return booleans
@classmethod
def get_wall_axis(cls, obj, layers=None):
x_values = [v[0] for v in obj.bound_box]
min_x = min(x_values)
max_x = max(x_values)
axes = {}
if layers:
axes = {
"base": [
(obj.matrix_world @ Vector((min_x, layers["offset"], 0.0))).to_2d(),
(obj.matrix_world @ Vector((max_x, layers["offset"], 0.0))).to_2d(),
],
"side": [
(obj.matrix_world @ Vector((min_x, layers["offset"] + layers["thickness"], 0.0))).to_2d(),
(obj.matrix_world @ Vector((max_x, layers["offset"] + layers["thickness"], 0.0))).to_2d(),
],
}
axes["reference"] = [
(obj.matrix_world @ Vector((min_x, 0.0, 0.0))).to_2d(),
(obj.matrix_world @ Vector((max_x, 0.0, 0.0))).to_2d(),
]
return axes