mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-12 10:33:20 +00:00
See #5919. You can now add openings through "Add Element" just like everything else.
This means that openings can (and default to) start with extrusions. It also starts to open up the possibility to add other types of feature elements. Still really incomplete.
This commit is contained in:
@@ -735,16 +735,10 @@ class OverrideDelete(bpy.types.Operator):
|
||||
else:
|
||||
bpy.data.objects.remove(obj)
|
||||
|
||||
while True:
|
||||
has_removed_opening = False
|
||||
openings = context.scene.BIMModelProperties.openings
|
||||
for i, opening in enumerate(openings):
|
||||
if not (element := tool.Ifc.get_entity(opening.obj)):
|
||||
has_removed_opening = True
|
||||
bpy.data.objects.remove(opening.obj)
|
||||
context.scene.BIMModelProperties.openings.remove(i)
|
||||
if not has_removed_opening:
|
||||
break
|
||||
for opening in context.scene.BIMModelProperties.openings:
|
||||
if not tool.Ifc.get_entity(opening.obj):
|
||||
bpy.data.objects.remove(opening.obj)
|
||||
tool.Model.purge_scene_openings()
|
||||
|
||||
if self.is_batch:
|
||||
old_file = tool.Ifc.get()
|
||||
|
||||
@@ -22,7 +22,6 @@ import ifcopenshell.util.element
|
||||
import ifcopenshell.util.schema
|
||||
from ifcopenshell.util.doc import get_entity_doc, get_predefined_type_doc, get_class_suggestions
|
||||
import bonsai.tool as tool
|
||||
from bonsai.bim.ifc import IfcStore
|
||||
from typing import Union
|
||||
|
||||
|
||||
@@ -58,6 +57,7 @@ class IfcClassData:
|
||||
products = [
|
||||
"IfcElementType",
|
||||
"IfcElement",
|
||||
"IfcFeatureElement",
|
||||
"IfcSpatialElement",
|
||||
"IfcSpatialElementType",
|
||||
"IfcStructuralItem",
|
||||
@@ -69,6 +69,7 @@ class IfcClassData:
|
||||
products = [
|
||||
"IfcElementType",
|
||||
"IfcElement",
|
||||
"IfcFeatureElement",
|
||||
"IfcSpatialStructureElement",
|
||||
"IfcStructuralItem",
|
||||
"IfcAnnotation",
|
||||
@@ -87,10 +88,11 @@ class IfcClassData:
|
||||
if tool.Ifc.get_schema() in ("IFC2X3", "IFC4"):
|
||||
names.extend(("IfcDoorStyle", "IfcWindowStyle"))
|
||||
if ifc_product == "IfcElement":
|
||||
names.remove("IfcOpeningElement")
|
||||
if tool.Ifc.get_schema() == "IFC4":
|
||||
# Yeah, weird isn't it.
|
||||
names.remove("IfcOpeningStandardCase")
|
||||
feature_elements = ifcopenshell.util.schema.get_subtypes(
|
||||
tool.Ifc.schema().declaration_by_name("IfcFeatureElement")
|
||||
)
|
||||
for feature_element in feature_elements:
|
||||
names.remove(feature_element.name())
|
||||
version = tool.Ifc.get_schema()
|
||||
return [(c, c, (get_entity_doc(version, c) or {}).get("description", "")) for c in sorted(names)]
|
||||
|
||||
|
||||
@@ -350,8 +350,13 @@ class AddElement(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _invoke(self, context, event):
|
||||
props = context.scene.BIMRootProperties
|
||||
# For convenience, preselect OBJ representation template if applicable
|
||||
if (obj := context.active_object) and obj.type == "MESH":
|
||||
# For convenience, preselect OBJs if applicable
|
||||
if props.ifc_product == "IfcFeatureElement":
|
||||
if (obj := tool.Blender.get_active_object(is_selected=True)) and obj.type == "MESH":
|
||||
props.featured_obj = obj
|
||||
props.representation_template = "EXTRUSION"
|
||||
props.representation_obj = None
|
||||
elif (obj := tool.Blender.get_active_object(is_selected=True)) and obj.type == "MESH":
|
||||
props.representation_template = "OBJ"
|
||||
props.representation_obj = obj
|
||||
# For convenience, preselect IFC class
|
||||
@@ -369,6 +374,9 @@ class AddElement(bpy.types.Operator, tool.Ifc.Operator):
|
||||
representation_template = props.representation_template
|
||||
ifc_file = tool.Ifc.get()
|
||||
|
||||
if props.ifc_product == "IfcFeatureElement" and not props.featured_obj:
|
||||
return self.report({"WARNING"}, "A featured element must be nominated.")
|
||||
|
||||
ifc_context = None
|
||||
if get_enum_items(props, "contexts", context):
|
||||
ifc_context = int(props.contexts or "0") or None
|
||||
@@ -556,6 +564,16 @@ class AddElement(bpy.types.Operator, tool.Ifc.Operator):
|
||||
elif representation_template == "ROOF":
|
||||
with context.temp_override(active_object=obj, selected_objects=[]):
|
||||
bpy.ops.bim.add_roof()
|
||||
|
||||
bpy.context.view_layer.update() # Ensures obj.matrix_world is correct
|
||||
|
||||
if props.ifc_product == "IfcFeatureElement":
|
||||
tool.Feature.add_feature(props.featured_obj, [obj])
|
||||
new = context.scene.BIMModelProperties.openings.add()
|
||||
new.obj = obj
|
||||
bpy.ops.bim.show_openings()
|
||||
tool.Model.purge_scene_openings()
|
||||
|
||||
bonsai.core.geometry.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=obj)
|
||||
tool.Blender.set_active_object(obj)
|
||||
|
||||
@@ -577,6 +595,9 @@ class AddElement(bpy.types.Operator, tool.Ifc.Operator):
|
||||
if props.ifc_predefined_type == "USERDEFINED":
|
||||
row = self.layout.row()
|
||||
row.prop(props, "ifc_userdefined_type")
|
||||
if props.ifc_product == "IfcFeatureElement":
|
||||
row = self.layout.row()
|
||||
row.prop(props, "featured_obj", text="Featured Object")
|
||||
prop_with_search(self.layout, props, "representation_template", text="Representation", should_click_ok=True)
|
||||
if props.representation_template == "OBJ":
|
||||
row = self.layout.row()
|
||||
|
||||
@@ -57,17 +57,26 @@ def refresh_classes(self, context):
|
||||
context.scene.BIMRootProperties.ifc_class = enum[0][0]
|
||||
IfcClassData.load()
|
||||
|
||||
if self.ifc_product == "IfcFeatureElement":
|
||||
if (obj := tool.Blender.get_active_object(is_selected=True)) and obj.type == "MESH":
|
||||
self.featured_obj = obj
|
||||
self.representation_template = "EXTRUSION"
|
||||
self.representation_obj = None
|
||||
elif (obj := tool.Blender.get_active_object(is_selected=True)) and obj.type == "MESH":
|
||||
self.representation_template = "OBJ"
|
||||
self.representation_obj = obj
|
||||
|
||||
# When switching between ElementType and Element, keep the same class and predefined type if possible
|
||||
if context.scene.BIMRootProperties.ifc_product == "IfcElement":
|
||||
if self.ifc_product == "IfcElement":
|
||||
ifc_class = next(iter(ifcopenshell.util.type.get_applicable_entities(old_class)), None)
|
||||
elif context.scene.BIMRootProperties.ifc_product == "IfcElementType":
|
||||
elif self.ifc_product == "IfcElementType":
|
||||
ifc_class = next(iter(ifcopenshell.util.type.get_applicable_types(old_class)), None)
|
||||
else:
|
||||
return
|
||||
if ifc_class:
|
||||
context.scene.BIMRootProperties.ifc_class = ifc_class
|
||||
self.ifc_class = ifc_class
|
||||
if old_predefined_type:
|
||||
context.scene.BIMRootProperties.ifc_predefined_type = old_predefined_type
|
||||
self.ifc_predefined_type = old_predefined_type
|
||||
|
||||
|
||||
def refresh_predefined_types(self, context):
|
||||
@@ -142,6 +151,10 @@ def poll_representation_obj(self, obj):
|
||||
return obj.type == "MESH" and obj.data.polygons
|
||||
|
||||
|
||||
def poll_featured_obj(self, obj):
|
||||
return tool.Ifc.get_entity(obj)
|
||||
|
||||
|
||||
class BIMRootProperties(PropertyGroup):
|
||||
contexts: EnumProperty(items=get_contexts, name="Contexts", options=set())
|
||||
name: StringProperty(name="Name")
|
||||
@@ -150,6 +163,12 @@ class BIMRootProperties(PropertyGroup):
|
||||
ifc_class: EnumProperty(items=get_ifc_classes, name="Class", update=refresh_predefined_types)
|
||||
ifc_predefined_type: EnumProperty(items=get_ifc_predefined_types, name="Predefined Type", default=None)
|
||||
ifc_userdefined_type: StringProperty(name="Userdefined Type")
|
||||
featured_obj: bpy.props.PointerProperty(
|
||||
type=bpy.types.Object,
|
||||
name="Featured Object",
|
||||
poll=poll_featured_obj,
|
||||
description="The feature will be applied to this object",
|
||||
)
|
||||
representation_template: bpy.props.EnumProperty(
|
||||
items=get_representation_template, name="Representation Template", default=0
|
||||
)
|
||||
|
||||
@@ -381,6 +381,10 @@ class Drawing:
|
||||
def update_text_value(cls, obj): pass
|
||||
|
||||
|
||||
@interface
|
||||
class Feature:
|
||||
def add_feature(cls, featured_obj, featured_objs): pass
|
||||
|
||||
@interface
|
||||
class Geometry:
|
||||
def change_object_data(cls, obj, data, is_global=False): pass
|
||||
|
||||
@@ -27,10 +27,13 @@ from bonsai.tool.clash import Clash
|
||||
from bonsai.tool.classification import Classification
|
||||
from bonsai.tool.collector import Collector
|
||||
from bonsai.tool.context import Context
|
||||
from bonsai.tool.cost import Cost
|
||||
from bonsai.tool.covering import Covering
|
||||
from bonsai.tool.debug import Debug
|
||||
from bonsai.tool.demo import Demo
|
||||
from bonsai.tool.document import Document
|
||||
from bonsai.tool.drawing import Drawing
|
||||
from bonsai.tool.feature import Feature
|
||||
from bonsai.tool.geometry import Geometry
|
||||
from bonsai.tool.georeference import Georeference
|
||||
from bonsai.tool.ifc import Ifc
|
||||
@@ -45,18 +48,18 @@ from bonsai.tool.nest import Nest
|
||||
from bonsai.tool.owner import Owner
|
||||
from bonsai.tool.patch import Patch
|
||||
from bonsai.tool.polyline import Polyline
|
||||
from bonsai.tool.project import Project
|
||||
from bonsai.tool.profile import Profile
|
||||
from bonsai.tool.project import Project
|
||||
from bonsai.tool.pset import Pset
|
||||
from bonsai.tool.pset_template import PsetTemplate
|
||||
from bonsai.tool.qto import Qto
|
||||
from bonsai.tool.raycast import Raycast
|
||||
from bonsai.tool.resource import Resource
|
||||
from bonsai.tool.root import Root
|
||||
from bonsai.tool.search import Search
|
||||
from bonsai.tool.sequence import Sequence
|
||||
from bonsai.tool.snap import Snap
|
||||
from bonsai.tool.spatial import Spatial
|
||||
from bonsai.tool.covering import Covering
|
||||
from bonsai.tool.structural import Structural
|
||||
from bonsai.tool.style import Style
|
||||
from bonsai.tool.surveyor import Surveyor
|
||||
@@ -64,6 +67,4 @@ from bonsai.tool.system import System
|
||||
from bonsai.tool.tester import Tester
|
||||
from bonsai.tool.type import Type
|
||||
from bonsai.tool.unit import Unit
|
||||
from bonsai.tool.search import Search
|
||||
from bonsai.tool.cost import Cost
|
||||
from bonsai.tool.web import Web
|
||||
|
||||
Reference in New Issue
Block a user