mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-25 01:50:02 +00:00
Filled openings now handle offset wall axes
This commit is contained in:
@@ -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}
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user