mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-10-01 20:49:44 +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:
|
else:
|
||||||
bpy.data.objects.remove(obj)
|
bpy.data.objects.remove(obj)
|
||||||
|
|
||||||
while True:
|
for opening in context.scene.BIMModelProperties.openings:
|
||||||
has_removed_opening = False
|
if not tool.Ifc.get_entity(opening.obj):
|
||||||
openings = context.scene.BIMModelProperties.openings
|
bpy.data.objects.remove(opening.obj)
|
||||||
for i, opening in enumerate(openings):
|
tool.Model.purge_scene_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
|
|
||||||
|
|
||||||
if self.is_batch:
|
if self.is_batch:
|
||||||
old_file = tool.Ifc.get()
|
old_file = tool.Ifc.get()
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import ifcopenshell.util.element
|
|||||||
import ifcopenshell.util.schema
|
import ifcopenshell.util.schema
|
||||||
from ifcopenshell.util.doc import get_entity_doc, get_predefined_type_doc, get_class_suggestions
|
from ifcopenshell.util.doc import get_entity_doc, get_predefined_type_doc, get_class_suggestions
|
||||||
import bonsai.tool as tool
|
import bonsai.tool as tool
|
||||||
from bonsai.bim.ifc import IfcStore
|
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
|
|
||||||
@@ -58,6 +57,7 @@ class IfcClassData:
|
|||||||
products = [
|
products = [
|
||||||
"IfcElementType",
|
"IfcElementType",
|
||||||
"IfcElement",
|
"IfcElement",
|
||||||
|
"IfcFeatureElement",
|
||||||
"IfcSpatialElement",
|
"IfcSpatialElement",
|
||||||
"IfcSpatialElementType",
|
"IfcSpatialElementType",
|
||||||
"IfcStructuralItem",
|
"IfcStructuralItem",
|
||||||
@@ -69,6 +69,7 @@ class IfcClassData:
|
|||||||
products = [
|
products = [
|
||||||
"IfcElementType",
|
"IfcElementType",
|
||||||
"IfcElement",
|
"IfcElement",
|
||||||
|
"IfcFeatureElement",
|
||||||
"IfcSpatialStructureElement",
|
"IfcSpatialStructureElement",
|
||||||
"IfcStructuralItem",
|
"IfcStructuralItem",
|
||||||
"IfcAnnotation",
|
"IfcAnnotation",
|
||||||
@@ -87,10 +88,11 @@ class IfcClassData:
|
|||||||
if tool.Ifc.get_schema() in ("IFC2X3", "IFC4"):
|
if tool.Ifc.get_schema() in ("IFC2X3", "IFC4"):
|
||||||
names.extend(("IfcDoorStyle", "IfcWindowStyle"))
|
names.extend(("IfcDoorStyle", "IfcWindowStyle"))
|
||||||
if ifc_product == "IfcElement":
|
if ifc_product == "IfcElement":
|
||||||
names.remove("IfcOpeningElement")
|
feature_elements = ifcopenshell.util.schema.get_subtypes(
|
||||||
if tool.Ifc.get_schema() == "IFC4":
|
tool.Ifc.schema().declaration_by_name("IfcFeatureElement")
|
||||||
# Yeah, weird isn't it.
|
)
|
||||||
names.remove("IfcOpeningStandardCase")
|
for feature_element in feature_elements:
|
||||||
|
names.remove(feature_element.name())
|
||||||
version = tool.Ifc.get_schema()
|
version = tool.Ifc.get_schema()
|
||||||
return [(c, c, (get_entity_doc(version, c) or {}).get("description", "")) for c in sorted(names)]
|
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):
|
def _invoke(self, context, event):
|
||||||
props = context.scene.BIMRootProperties
|
props = context.scene.BIMRootProperties
|
||||||
# For convenience, preselect OBJ representation template if applicable
|
# For convenience, preselect OBJs if applicable
|
||||||
if (obj := context.active_object) and obj.type == "MESH":
|
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_template = "OBJ"
|
||||||
props.representation_obj = obj
|
props.representation_obj = obj
|
||||||
# For convenience, preselect IFC class
|
# For convenience, preselect IFC class
|
||||||
@@ -369,6 +374,9 @@ class AddElement(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
representation_template = props.representation_template
|
representation_template = props.representation_template
|
||||||
ifc_file = tool.Ifc.get()
|
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
|
ifc_context = None
|
||||||
if get_enum_items(props, "contexts", context):
|
if get_enum_items(props, "contexts", context):
|
||||||
ifc_context = int(props.contexts or "0") or None
|
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":
|
elif representation_template == "ROOF":
|
||||||
with context.temp_override(active_object=obj, selected_objects=[]):
|
with context.temp_override(active_object=obj, selected_objects=[]):
|
||||||
bpy.ops.bim.add_roof()
|
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)
|
bonsai.core.geometry.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=obj)
|
||||||
tool.Blender.set_active_object(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":
|
if props.ifc_predefined_type == "USERDEFINED":
|
||||||
row = self.layout.row()
|
row = self.layout.row()
|
||||||
row.prop(props, "ifc_userdefined_type")
|
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)
|
prop_with_search(self.layout, props, "representation_template", text="Representation", should_click_ok=True)
|
||||||
if props.representation_template == "OBJ":
|
if props.representation_template == "OBJ":
|
||||||
row = self.layout.row()
|
row = self.layout.row()
|
||||||
|
|||||||
@@ -57,17 +57,26 @@ def refresh_classes(self, context):
|
|||||||
context.scene.BIMRootProperties.ifc_class = enum[0][0]
|
context.scene.BIMRootProperties.ifc_class = enum[0][0]
|
||||||
IfcClassData.load()
|
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
|
# 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)
|
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)
|
ifc_class = next(iter(ifcopenshell.util.type.get_applicable_types(old_class)), None)
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
if ifc_class:
|
if ifc_class:
|
||||||
context.scene.BIMRootProperties.ifc_class = ifc_class
|
self.ifc_class = ifc_class
|
||||||
if old_predefined_type:
|
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):
|
def refresh_predefined_types(self, context):
|
||||||
@@ -142,6 +151,10 @@ def poll_representation_obj(self, obj):
|
|||||||
return obj.type == "MESH" and obj.data.polygons
|
return obj.type == "MESH" and obj.data.polygons
|
||||||
|
|
||||||
|
|
||||||
|
def poll_featured_obj(self, obj):
|
||||||
|
return tool.Ifc.get_entity(obj)
|
||||||
|
|
||||||
|
|
||||||
class BIMRootProperties(PropertyGroup):
|
class BIMRootProperties(PropertyGroup):
|
||||||
contexts: EnumProperty(items=get_contexts, name="Contexts", options=set())
|
contexts: EnumProperty(items=get_contexts, name="Contexts", options=set())
|
||||||
name: StringProperty(name="Name")
|
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_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_predefined_type: EnumProperty(items=get_ifc_predefined_types, name="Predefined Type", default=None)
|
||||||
ifc_userdefined_type: StringProperty(name="Userdefined Type")
|
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(
|
representation_template: bpy.props.EnumProperty(
|
||||||
items=get_representation_template, name="Representation Template", default=0
|
items=get_representation_template, name="Representation Template", default=0
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -381,6 +381,10 @@ class Drawing:
|
|||||||
def update_text_value(cls, obj): pass
|
def update_text_value(cls, obj): pass
|
||||||
|
|
||||||
|
|
||||||
|
@interface
|
||||||
|
class Feature:
|
||||||
|
def add_feature(cls, featured_obj, featured_objs): pass
|
||||||
|
|
||||||
@interface
|
@interface
|
||||||
class Geometry:
|
class Geometry:
|
||||||
def change_object_data(cls, obj, data, is_global=False): pass
|
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.classification import Classification
|
||||||
from bonsai.tool.collector import Collector
|
from bonsai.tool.collector import Collector
|
||||||
from bonsai.tool.context import Context
|
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.debug import Debug
|
||||||
from bonsai.tool.demo import Demo
|
from bonsai.tool.demo import Demo
|
||||||
from bonsai.tool.document import Document
|
from bonsai.tool.document import Document
|
||||||
from bonsai.tool.drawing import Drawing
|
from bonsai.tool.drawing import Drawing
|
||||||
|
from bonsai.tool.feature import Feature
|
||||||
from bonsai.tool.geometry import Geometry
|
from bonsai.tool.geometry import Geometry
|
||||||
from bonsai.tool.georeference import Georeference
|
from bonsai.tool.georeference import Georeference
|
||||||
from bonsai.tool.ifc import Ifc
|
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.owner import Owner
|
||||||
from bonsai.tool.patch import Patch
|
from bonsai.tool.patch import Patch
|
||||||
from bonsai.tool.polyline import Polyline
|
from bonsai.tool.polyline import Polyline
|
||||||
from bonsai.tool.project import Project
|
|
||||||
from bonsai.tool.profile import Profile
|
from bonsai.tool.profile import Profile
|
||||||
|
from bonsai.tool.project import Project
|
||||||
from bonsai.tool.pset import Pset
|
from bonsai.tool.pset import Pset
|
||||||
from bonsai.tool.pset_template import PsetTemplate
|
from bonsai.tool.pset_template import PsetTemplate
|
||||||
from bonsai.tool.qto import Qto
|
from bonsai.tool.qto import Qto
|
||||||
from bonsai.tool.raycast import Raycast
|
from bonsai.tool.raycast import Raycast
|
||||||
from bonsai.tool.resource import Resource
|
from bonsai.tool.resource import Resource
|
||||||
from bonsai.tool.root import Root
|
from bonsai.tool.root import Root
|
||||||
|
from bonsai.tool.search import Search
|
||||||
from bonsai.tool.sequence import Sequence
|
from bonsai.tool.sequence import Sequence
|
||||||
from bonsai.tool.snap import Snap
|
from bonsai.tool.snap import Snap
|
||||||
from bonsai.tool.spatial import Spatial
|
from bonsai.tool.spatial import Spatial
|
||||||
from bonsai.tool.covering import Covering
|
|
||||||
from bonsai.tool.structural import Structural
|
from bonsai.tool.structural import Structural
|
||||||
from bonsai.tool.style import Style
|
from bonsai.tool.style import Style
|
||||||
from bonsai.tool.surveyor import Surveyor
|
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.tester import Tester
|
||||||
from bonsai.tool.type import Type
|
from bonsai.tool.type import Type
|
||||||
from bonsai.tool.unit import Unit
|
from bonsai.tool.unit import Unit
|
||||||
from bonsai.tool.search import Search
|
|
||||||
from bonsai.tool.cost import Cost
|
|
||||||
from bonsai.tool.web import Web
|
from bonsai.tool.web import Web
|
||||||
|
|||||||
Reference in New Issue
Block a user