See #5919. API now has support for features, not just openings. Void module is renamed to feature.

This commit is contained in:
Dion Moult
2025-01-28 14:18:17 +11:00
parent 5300f4c78f
commit 03bfd828e2
21 changed files with 326 additions and 132 deletions
@@ -26,7 +26,7 @@ import numpy as np
import ifcopenshell
import ifcopenshell.api
import ifcopenshell.api.geometry
import ifcopenshell.api.void
import ifcopenshell.api.feature
import ifcopenshell.geom
import ifcopenshell.util.shape
import ifcopenshell.util.element
@@ -69,7 +69,7 @@ class FilledOpeningGenerator:
assert filling and element
if filling.FillsVoids:
ifcopenshell.api.run(
"void.remove_opening", tool.Ifc.get(), opening=filling.FillsVoids[0].RelatingOpeningElement
"feature.remove_feature", tool.Ifc.get(), feature=filling.FillsVoids[0].RelatingOpeningElement
)
if target is None:
@@ -156,8 +156,8 @@ class FilledOpeningGenerator:
"geometry.assign_representation", tool.Ifc.get(), product=opening, representation=mapped_representation
)
ifcopenshell.api.run("void.add_opening", tool.Ifc.get(), opening=opening, element=element)
ifcopenshell.api.run("void.add_filling", tool.Ifc.get(), opening=opening, element=filling)
ifcopenshell.api.run("feature.add_feature", tool.Ifc.get(), feature=opening, element=element)
ifcopenshell.api.run("feature.add_filling", tool.Ifc.get(), opening=opening, element=filling)
voided_objs = [voided_obj]
# Openings affect all subelements of an aggregate
@@ -826,7 +826,7 @@ class CloneOpening(Operator, tool.Ifc.Operator):
new_opening = ifcopenshell.api.run("root.create_entity", tool.Ifc.get(), ifc_class="IfcOpeningElement")
new_opening.Representation = opening_representation
ifcopenshell.api.void.add_opening(ifc_file, opening=new_opening, element=voided_element)
ifcopenshell.api.feature.add_feature(ifc_file, feature=new_opening, element=voided_element)
new_opening.ObjectPlacement = opening_placement
# Update affected representations.
+2 -2
View File
@@ -984,7 +984,7 @@ class DumbWallJoiner:
_, opening_position = mathutils.geometry.intersect_point_line(opening_location.to_2d(), *axis1["reference"])
if opening_position > cut_percentage:
# The opening should be removed from element1.
ifcopenshell.api.run("void.remove_opening", tool.Ifc.get(), opening=opening)
ifcopenshell.api.run("feature.remove_feature", tool.Ifc.get(), feature=opening)
# Now let's check element2.
for opening in [
@@ -996,7 +996,7 @@ class DumbWallJoiner:
_, opening_position = mathutils.geometry.intersect_point_line(opening_location.to_2d(), *axis1["reference"])
if opening_position < cut_percentage:
# The opening should be removed from element2.
ifcopenshell.api.run("void.remove_opening", tool.Ifc.get(), opening=opening)
ifcopenshell.api.run("feature.remove_feature", tool.Ifc.get(), feature=opening)
# During the duplication process, filled voids are not copied. So we
# only need to check fillings on the original element1.
@@ -87,7 +87,7 @@ class AddOpening(bpy.types.Operator, tool.Ifc.Operator):
self.report({"INFO"}, f"An {element1.is_a()} is not allowed to have an opening.")
continue
# Sync placement before void.add_opening.
# Sync placement before feature.add_feature.
if tool.Ifc.is_moved(obj1):
bonsai.core.geometry.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=obj1)
@@ -109,7 +109,7 @@ class AddOpening(bpy.types.Operator, tool.Ifc.Operator):
should_add_representation=True,
context=body_context,
)
ifcopenshell.api.run("void.add_opening", tool.Ifc.get(), opening=element2, element=element1)
ifcopenshell.api.run("feature.add_feature", tool.Ifc.get(), feature=element2, element=element1)
if tool.Ifc.is_moved(obj2):
bonsai.core.geometry.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=obj2)
@@ -178,7 +178,7 @@ class RemoveOpening(bpy.types.Operator, tool.Ifc.Operator):
opening_obj.name = "/".join(opening_obj.name.split("/")[1:])
tool.Ifc.unlink(element=opening)
ifcopenshell.api.run("void.remove_opening", tool.Ifc.get(), opening=opening)
ifcopenshell.api.run("feature.remove_feature", tool.Ifc.get(), feature=opening)
decomposed_building_elements = {element}
decomposed_building_elements.update(tool.Aggregate.get_parts_recursively(element))
@@ -220,7 +220,7 @@ class AddFilling(bpy.types.Operator, tool.Ifc.Operator):
if not element_id or not opening_id or element_id == opening_id:
return {"FINISHED"}
ifcopenshell.api.run(
"void.add_filling", self.file, opening=self.file.by_id(opening_id), element=self.file.by_id(element_id)
"feature.add_filling", self.file, opening=self.file.by_id(opening_id), element=self.file.by_id(element_id)
)
return {"FINISHED"}
@@ -233,10 +233,9 @@ class RemoveFilling(bpy.types.Operator, tool.Ifc.Operator):
def _execute(self, context):
filling = tool.Ifc.get().by_id(self.filling)
filling_obj = tool.Ifc.get_object(filling)
for rel in filling.FillsVoids:
bpy.ops.bim.remove_opening(opening_id=rel.RelatingOpeningElement.id())
ifcopenshell.api.run("void.remove_filling", tool.Ifc.get(), element=filling)
ifcopenshell.api.run("feature.remove_filling", tool.Ifc.get(), element=filling)
return {"FINISHED"}
+2 -2
View File
@@ -40,13 +40,13 @@ class Feature(bonsai.core.tool.Feature):
for feature_obj in feature_objs:
feature_element = tool.Ifc.get_entity(feature_obj)
# Sync placement before void.add_opening.
# Sync placement before feature.add_feature.
if tool.Ifc.is_moved(featured_obj):
bonsai.core.geometry.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=featured_obj)
element_had_openings = tool.Geometry.has_openings(featured_element)
body_context = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body")
ifcopenshell.api.run("void.add_opening", tool.Ifc.get(), opening=feature_element, element=featured_element)
ifcopenshell.api.run("feature.add_feature", tool.Ifc.get(), feature=feature_element, element=featured_element)
if tool.Ifc.is_moved(feature_obj):
bonsai.core.geometry.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=feature_obj)
+2 -2
View File
@@ -290,8 +290,8 @@ class Root(bonsai.core.tool.Root):
product=opening,
representation=mapped_representation,
)
ifcopenshell.api.run("void.add_opening", tool.Ifc.get(), opening=opening, element=element)
ifcopenshell.api.run("void.add_filling", tool.Ifc.get(), opening=opening, element=filling)
ifcopenshell.api.run("feature.add_feature", tool.Ifc.get(), feature=opening, element=element)
ifcopenshell.api.run("feature.add_filling", tool.Ifc.get(), opening=opening, element=filling)
voided_objs = [voided_obj]
# Openings affect all subelements of an aggregate
+2 -2
View File
@@ -74,8 +74,8 @@ class TestGetDecompositionRelationships(NewFile):
element = ifc.createIfcWall()
opening = ifc.createIfcOpeningElement()
fill = ifc.createIfcWindow()
ifcopenshell.api.run("void.add_opening", ifc, opening=opening, element=element)
ifcopenshell.api.run("void.add_filling", ifc, opening=opening, element=fill)
ifcopenshell.api.run("feature.add_feature", ifc, feature=opening, element=element)
ifcopenshell.api.run("feature.add_filling", ifc, opening=opening, element=fill)
obj = bpy.data.objects.new("Object", None)
tool.Ifc.link(fill, obj)