mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-19 19:54:07 +00:00
Add axis support to new wall engine
This commit is contained in:
@@ -655,6 +655,7 @@ class DumbWallGenerator:
|
|||||||
return
|
return
|
||||||
|
|
||||||
self.body_context = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body", "MODEL_VIEW")
|
self.body_context = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body", "MODEL_VIEW")
|
||||||
|
self.axis_context = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Plan", "Axis", "GRAPH_VIEW")
|
||||||
|
|
||||||
self.collection = bpy.context.view_layer.active_layer_collection.collection
|
self.collection = bpy.context.view_layer.active_layer_collection.collection
|
||||||
self.collection_obj = bpy.data.objects.get(self.collection.name)
|
self.collection_obj = bpy.data.objects.get(self.collection.name)
|
||||||
@@ -753,7 +754,11 @@ class DumbWallGenerator:
|
|||||||
if "IfcWall" not in sibling_obj.name:
|
if "IfcWall" not in sibling_obj.name:
|
||||||
continue
|
continue
|
||||||
local_location = sibling_obj.matrix_world.inverted() @ self.location
|
local_location = sibling_obj.matrix_world.inverted() @ self.location
|
||||||
raycast = sibling_obj.closest_point_on_mesh(local_location, distance=0.01)
|
try:
|
||||||
|
raycast = sibling_obj.closest_point_on_mesh(local_location, distance=0.01)
|
||||||
|
except:
|
||||||
|
# If the mesh has no faces
|
||||||
|
raycast = [None]
|
||||||
if not raycast[0]:
|
if not raycast[0]:
|
||||||
continue
|
continue
|
||||||
for face in sibling_obj.data.polygons:
|
for face in sibling_obj.data.polygons:
|
||||||
@@ -769,15 +774,6 @@ class DumbWallGenerator:
|
|||||||
return self.create_wall()
|
return self.create_wall()
|
||||||
|
|
||||||
def create_wall(self):
|
def create_wall(self):
|
||||||
representation = ifcopenshell.api.run(
|
|
||||||
"geometry.add_wall_representation",
|
|
||||||
tool.Ifc.get(),
|
|
||||||
context=self.body_context,
|
|
||||||
thickness=self.layers["thickness"],
|
|
||||||
offset=self.layers["offset"],
|
|
||||||
length=self.length,
|
|
||||||
height=self.height,
|
|
||||||
)
|
|
||||||
ifc_class = self.get_relating_type_class(self.relating_type)
|
ifc_class = self.get_relating_type_class(self.relating_type)
|
||||||
mesh = bpy.data.meshes.new("Dummy")
|
mesh = bpy.data.meshes.new("Dummy")
|
||||||
obj = bpy.data.objects.new(tool.Model.generate_occurrence_name(self.relating_type, ifc_class), mesh)
|
obj = bpy.data.objects.new(tool.Model.generate_occurrence_name(self.relating_type, ifc_class), mesh)
|
||||||
@@ -796,6 +792,25 @@ class DumbWallGenerator:
|
|||||||
should_add_representation=False,
|
should_add_representation=False,
|
||||||
context=self.body_context,
|
context=self.body_context,
|
||||||
)
|
)
|
||||||
|
if self.axis_context:
|
||||||
|
representation = ifcopenshell.api.run(
|
||||||
|
"geometry.add_axis_representation",
|
||||||
|
tool.Ifc.get(),
|
||||||
|
context=self.axis_context,
|
||||||
|
axis=[(0., 0.,), (self.length, 0.)],
|
||||||
|
)
|
||||||
|
ifcopenshell.api.run(
|
||||||
|
"geometry.assign_representation", tool.Ifc.get(), product=element, representation=representation
|
||||||
|
)
|
||||||
|
representation = ifcopenshell.api.run(
|
||||||
|
"geometry.add_wall_representation",
|
||||||
|
tool.Ifc.get(),
|
||||||
|
context=self.body_context,
|
||||||
|
thickness=self.layers["thickness"],
|
||||||
|
offset=self.layers["offset"],
|
||||||
|
length=self.length,
|
||||||
|
height=self.height,
|
||||||
|
)
|
||||||
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
|
||||||
)
|
)
|
||||||
@@ -1041,6 +1056,7 @@ class WallPrototypeVTX(bpy.types.Operator):
|
|||||||
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||||
self.axis_context = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Plan", "AXIS", "GRAPH_VIEW")
|
self.axis_context = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Plan", "AXIS", "GRAPH_VIEW")
|
||||||
self.body_context = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body", "MODEL_VIEW")
|
self.body_context = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body", "MODEL_VIEW")
|
||||||
|
self.axis_context = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Plan", "Axis", "GRAPH_VIEW")
|
||||||
|
|
||||||
selected_objects = [o for o in context.selected_objects if tool.Ifc.get_entity(o)]
|
selected_objects = [o for o in context.selected_objects if tool.Ifc.get_entity(o)]
|
||||||
if len(selected_objects) == 1:
|
if len(selected_objects) == 1:
|
||||||
@@ -1062,7 +1078,11 @@ class WallPrototypeVTX(bpy.types.Operator):
|
|||||||
element2 = tool.Ifc.get_entity(wall2)
|
element2 = tool.Ifc.get_entity(wall2)
|
||||||
axis1 = self.get_wall_axis(wall1)
|
axis1 = self.get_wall_axis(wall1)
|
||||||
axis2 = self.get_wall_axis(wall2)
|
axis2 = self.get_wall_axis(wall2)
|
||||||
intersect, _ = tool.Cad.intersect_edges(axis1["reference"], axis2["reference"])
|
intersect = tool.Cad.intersect_edges(axis1["reference"], axis2["reference"])
|
||||||
|
if intersect:
|
||||||
|
intersect, _ = intersect
|
||||||
|
else:
|
||||||
|
return
|
||||||
wall1_end = "ATEND" if tool.Cad.edge_percent(intersect, axis1["reference"]) > 0.5 else "ATSTART"
|
wall1_end = "ATEND" if tool.Cad.edge_percent(intersect, axis1["reference"]) > 0.5 else "ATSTART"
|
||||||
wall2_end = "ATEND" if tool.Cad.edge_percent(intersect, axis2["reference"]) > 0.5 else "ATSTART"
|
wall2_end = "ATEND" if tool.Cad.edge_percent(intersect, axis2["reference"]) > 0.5 else "ATSTART"
|
||||||
|
|
||||||
@@ -1087,9 +1107,7 @@ class WallPrototypeVTX(bpy.types.Operator):
|
|||||||
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"
|
||||||
|
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run("geometry.disconnect_path", tool.Ifc.get(), element=element1, connection_type=connection)
|
||||||
"geometry.disconnect_path", tool.Ifc.get(), element=element1, connection_type=connection
|
|
||||||
)
|
|
||||||
|
|
||||||
axis = axis1["reference"].copy()
|
axis = axis1["reference"].copy()
|
||||||
body = axis1["reference"].copy()
|
body = axis1["reference"].copy()
|
||||||
@@ -1102,7 +1120,11 @@ class WallPrototypeVTX(bpy.types.Operator):
|
|||||||
element2 = tool.Ifc.get_entity(wall2)
|
element2 = tool.Ifc.get_entity(wall2)
|
||||||
axis1 = self.get_wall_axis(wall1)
|
axis1 = self.get_wall_axis(wall1)
|
||||||
axis2 = self.get_wall_axis(wall2)
|
axis2 = self.get_wall_axis(wall2)
|
||||||
intersect, _ = tool.Cad.intersect_edges(axis1["reference"], axis2["reference"])
|
intersect = tool.Cad.intersect_edges(axis1["reference"], axis2["reference"])
|
||||||
|
if intersect:
|
||||||
|
intersect, _ = intersect
|
||||||
|
else:
|
||||||
|
return
|
||||||
connection = "ATEND" if tool.Cad.edge_percent(intersect, axis1["reference"]) > 0.5 else "ATSTART"
|
connection = "ATEND" if tool.Cad.edge_percent(intersect, axis1["reference"]) > 0.5 else "ATSTART"
|
||||||
|
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
@@ -1140,7 +1162,25 @@ class WallPrototypeVTX(bpy.types.Operator):
|
|||||||
self.clippings = [new_matrix @ c for c in self.clippings]
|
self.clippings = [new_matrix @ c for c in self.clippings]
|
||||||
|
|
||||||
length = (self.body[1] - self.body[0]).length
|
length = (self.body[1] - self.body[0]).length
|
||||||
new_representation = ifcopenshell.api.run(
|
|
||||||
|
if self.axis_context:
|
||||||
|
axis = [(new_matrix @ a.to_3d()).to_2d() for a in self.axis]
|
||||||
|
new_axis = ifcopenshell.api.run(
|
||||||
|
"geometry.add_axis_representation", tool.Ifc.get(), context=self.axis_context, axis=axis
|
||||||
|
)
|
||||||
|
old_axis = ifcopenshell.util.representation.get_representation(element, "Plan", "Axis", "GRAPH_VIEW")
|
||||||
|
if old_axis:
|
||||||
|
for inverse in tool.Ifc.get().get_inverse(old_axis):
|
||||||
|
ifcopenshell.util.element.replace_attribute(inverse, old_axis, new_axis)
|
||||||
|
blenderbim.core.geometry.remove_representation(
|
||||||
|
tool.Ifc, tool.Geometry, obj=obj, representation=old_axis
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
ifcopenshell.api.run(
|
||||||
|
"geometry.assign_representation", tool.Ifc.get(), product=element, representation=new_axis
|
||||||
|
)
|
||||||
|
|
||||||
|
new_body = ifcopenshell.api.run(
|
||||||
"geometry.add_wall_representation",
|
"geometry.add_wall_representation",
|
||||||
tool.Ifc.get(),
|
tool.Ifc.get(),
|
||||||
context=self.body_context,
|
context=self.body_context,
|
||||||
@@ -1151,19 +1191,22 @@ class WallPrototypeVTX(bpy.types.Operator):
|
|||||||
clippings=self.clippings,
|
clippings=self.clippings,
|
||||||
)
|
)
|
||||||
|
|
||||||
old_representation = tool.Ifc.get().by_id(obj.data.BIMMeshProperties.ifc_definition_id)
|
old_body = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
|
||||||
for inverse in tool.Ifc.get().get_inverse(old_representation):
|
if old_body:
|
||||||
ifcopenshell.util.element.replace_attribute(inverse, old_representation, new_representation)
|
for inverse in tool.Ifc.get().get_inverse(old_body):
|
||||||
obj.data.BIMMeshProperties.ifc_definition_id = int(new_representation.id())
|
ifcopenshell.util.element.replace_attribute(inverse, old_body, new_body)
|
||||||
obj.data.name = f"{old_representation.ContextOfItems.id()}/{new_representation.id()}"
|
obj.data.BIMMeshProperties.ifc_definition_id = int(new_body.id())
|
||||||
blenderbim.core.geometry.remove_representation(
|
obj.data.name = f"{self.body_context.id()}/{new_body.id()}"
|
||||||
tool.Ifc, tool.Geometry, obj=obj, representation=old_representation
|
blenderbim.core.geometry.remove_representation(tool.Ifc, tool.Geometry, obj=obj, representation=old_body)
|
||||||
)
|
else:
|
||||||
|
ifcopenshell.api.run(
|
||||||
|
"geometry.assign_representation", tool.Ifc.get(), product=element, representation=new_body
|
||||||
|
)
|
||||||
|
|
||||||
blenderbim.core.geometry.switch_representation(
|
blenderbim.core.geometry.switch_representation(
|
||||||
tool.Geometry,
|
tool.Geometry,
|
||||||
obj=obj,
|
obj=obj,
|
||||||
representation=new_representation,
|
representation=new_body,
|
||||||
should_reload=True,
|
should_reload=True,
|
||||||
enable_dynamic_voids=False,
|
enable_dynamic_voids=False,
|
||||||
is_global=True,
|
is_global=True,
|
||||||
@@ -1226,11 +1269,15 @@ class WallPrototypeVTX(bpy.types.Operator):
|
|||||||
axis2 = self.get_wall_axis(wall2, layers2)
|
axis2 = self.get_wall_axis(wall2, layers2)
|
||||||
|
|
||||||
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 tool.Cad.is_x(angle, 0):
|
if tool.Cad.is_x(angle, (0, 180)):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Work out axis line
|
# Work out axis line
|
||||||
intersect, _ = tool.Cad.intersect_edges(axis1["reference"], axis2["reference"])
|
intersect = tool.Cad.intersect_edges(axis1["reference"], axis2["reference"])
|
||||||
|
if intersect:
|
||||||
|
intersect, _ = intersect
|
||||||
|
else:
|
||||||
|
return
|
||||||
self.axis[1 if connection == "ATEND" else 0] = intersect
|
self.axis[1 if connection == "ATEND" else 0] = intersect
|
||||||
|
|
||||||
# Work out body extents
|
# Work out body extents
|
||||||
@@ -1247,7 +1294,7 @@ class WallPrototypeVTX(bpy.types.Operator):
|
|||||||
base_target = tool.Cad.furthest_vector(axis1["base"][0], (intersect1, intersect2))
|
base_target = tool.Cad.furthest_vector(axis1["base"][0], (intersect1, intersect2))
|
||||||
else:
|
else:
|
||||||
base_target = tool.Cad.closest_vector(axis1["base"][0], (intersect1, intersect2))
|
base_target = tool.Cad.closest_vector(axis1["base"][0], (intersect1, intersect2))
|
||||||
if tool.Cad.is_x(angle, 90):
|
if tool.Cad.is_x(angle, (90, 270)):
|
||||||
self.body[1] = tool.Cad.point_on_edge(base_target, axis1["reference"])
|
self.body[1] = tool.Cad.point_on_edge(base_target, axis1["reference"])
|
||||||
else:
|
else:
|
||||||
if is_relating:
|
if is_relating:
|
||||||
@@ -1275,7 +1322,7 @@ class WallPrototypeVTX(bpy.types.Operator):
|
|||||||
base_target = tool.Cad.furthest_vector(axis1["base"][1], (intersect1, intersect2))
|
base_target = tool.Cad.furthest_vector(axis1["base"][1], (intersect1, intersect2))
|
||||||
else:
|
else:
|
||||||
base_target = tool.Cad.closest_vector(axis1["base"][1], (intersect1, intersect2))
|
base_target = tool.Cad.closest_vector(axis1["base"][1], (intersect1, intersect2))
|
||||||
if tool.Cad.is_x(angle, 90):
|
if tool.Cad.is_x(angle, (90, 270)):
|
||||||
self.body[0] = tool.Cad.point_on_edge(base_target, axis1["reference"])
|
self.body[0] = tool.Cad.point_on_edge(base_target, axis1["reference"])
|
||||||
else:
|
else:
|
||||||
if is_relating:
|
if is_relating:
|
||||||
|
|||||||
@@ -79,15 +79,20 @@ class Cad:
|
|||||||
if signed:
|
if signed:
|
||||||
a = (edge1[1] - edge1[0]).angle_signed(edge2[1] - edge2[0])
|
a = (edge1[1] - edge1[0]).angle_signed(edge2[1] - edge2[0])
|
||||||
else:
|
else:
|
||||||
a = (edge1[1] - edge1[0]).angle_signed(edge2[1] - edge2[0])
|
a = (edge1[1] - edge1[0]).angle(edge2[1] - edge2[0])
|
||||||
return math.degrees(a) if degrees else a
|
return math.degrees(a) if degrees else a
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_x(cls, value, x):
|
def is_x(cls, value, x):
|
||||||
"""
|
"""
|
||||||
> takes a value and a target of x
|
> takes a value and a target of x, either as a single value x or an interable of values
|
||||||
< returns if the value is equivalent to x within a tolerance
|
< returns if the value is equivalent to x within a tolerance
|
||||||
"""
|
"""
|
||||||
|
if isinstance(x, (list, tuple)):
|
||||||
|
for y in x:
|
||||||
|
if value > (y - VTX_PRECISION) and value < (y + VTX_PRECISION):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
return value > (x - VTX_PRECISION) and value < (x + VTX_PRECISION)
|
return value > (x - VTX_PRECISION) and value < (x + VTX_PRECISION)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
Reference in New Issue
Block a user