diff --git a/src/blenderbim/blenderbim/bim/module/clash/data.py b/src/blenderbim/blenderbim/bim/module/clash/data.py
index f6e788b82a..7f61222f7b 100644
--- a/src/blenderbim/blenderbim/bim/module/clash/data.py
+++ b/src/blenderbim/blenderbim/bim/module/clash/data.py
@@ -17,138 +17,36 @@
# along with BlenderBIM Add-on. If not, see .
import bpy
-import ifcopenshell
-import ifcopenshell.util.date
-import ifcopenshell.util.classification
+import json
+import ifcopenshell.util.element
import blenderbim.tool as tool
-from blenderbim.bim.ifc import IfcStore
def refresh():
- ClassificationsData.is_loaded = False
- ClassificationReferencesData.is_loaded = False
- MaterialClassificationsData.is_loaded = False
- CostClassificationsData.is_loaded = False
+ ClashData.is_loaded = False
-class ClassificationsData:
+class ClashData:
data = {}
is_loaded = False
@classmethod
def load(cls):
cls.is_loaded = True
- cls.data["has_classification_file"] = cls.has_classification_file()
- cls.data["classifications"] = cls.classifications()
- cls.data["available_classifications"] = cls.available_classifications()
+ cls.data = {}
+ cls.data["saved_searches"] = cls.saved_searches()
@classmethod
- def has_classification_file(cls):
- return bool(IfcStore.classification_file)
-
- @classmethod
- def classifications(cls):
- results = []
- for element in tool.Ifc.get().by_type("IfcClassification"):
- data = element.get_info()
- if tool.Ifc.get().schema == "IFC2X3" and element.EditionDate:
- data["EditionDate"] = ifcopenshell.util.date.ifc2datetime(data["EditionDate"])
- results.append(data)
- return results
-
- @classmethod
- def available_classifications(cls):
- if not IfcStore.classification_file:
+ def saved_searches(cls):
+ if not tool.Ifc.get():
return []
- return [(str(e.id()), e.Name, "") for e in IfcStore.classification_file.by_type("IfcClassification")]
-
-
-class ReferencesData:
- @classmethod
- def active_classification_library(cls):
- if not IfcStore.classification_file or not IfcStore.classification_file.by_type("IfcClassification"):
- return False
- props = bpy.context.scene.BIMClassificationProperties
- name = IfcStore.classification_file.by_id(int(props.available_classifications)).Name
- if name in [e.Name for e in tool.Ifc.get().by_type("IfcClassification")]:
- return name
-
- @classmethod
- def classifications(cls):
- return [(str(e.id()), e.Name, "") for e in tool.Ifc.get().by_type("IfcClassification")]
-
-
-class ClassificationReferencesData(ReferencesData):
- data = {}
- is_loaded = False
-
- @classmethod
- def load(cls):
- cls.is_loaded = True
- cls.data["references"] = cls.references()
- cls.data["active_classification_library"] = cls.active_classification_library()
- cls.data["classifications"] = cls.classifications()
- cls.data["object_type"] = "OBJECT"
-
- @classmethod
- def references(cls):
+ groups = tool.Ifc.get().by_type("IfcGroup")
results = []
- element = tool.Ifc.get_entity(bpy.context.active_object)
- if element:
- for reference in ifcopenshell.util.classification.get_references(element):
- data = reference.get_info()
- del data["ReferencedSource"]
- results.append(data)
- return results
-
-
-class MaterialClassificationsData(ReferencesData):
- data = {}
- is_loaded = False
-
- @classmethod
- def load(cls):
- cls.is_loaded = True
- cls.data["references"] = cls.references()
- cls.data["active_classification_library"] = cls.active_classification_library()
- cls.data["classifications"] = cls.classifications()
- cls.data["object_type"] = "MATERIAL"
-
- @classmethod
- def references(cls):
- results = []
- element = tool.Ifc.get_entity(bpy.context.active_object.active_material)
- if element:
- for reference in ifcopenshell.util.classification.get_references(element):
- data = reference.get_info()
- del data["ReferencedSource"]
- results.append(data)
- return results
-
-
-class CostClassificationsData(ReferencesData):
- data = {}
- is_loaded = False
-
- @classmethod
- def load(cls):
- cls.is_loaded = True
- cls.data["references"] = cls.references()
- cls.data["active_classification_library"] = cls.active_classification_library()
- cls.data["classifications"] = cls.classifications()
- cls.data["object_type"] = "COST"
-
- @classmethod
- def references(cls):
- results = []
- element = tool.Ifc.get().by_id(
- bpy.context.scene.BIMCostProperties.cost_items[
- bpy.context.scene.BIMCostProperties.active_cost_item_index
- ].ifc_definition_id
- )
- if element:
- for reference in ifcopenshell.util.classification.get_references(element):
- data = reference.get_info()
- del data["ReferencedSource"]
- results.append(data)
- return results
+ for group in groups:
+ try:
+ data = json.loads(group.Description)
+ if isinstance(data, dict) and data.get("type", None) == "BBIM_Search" and data.get("query", None):
+ results.append(group)
+ except:
+ pass
+ return [(str(g.id()), g.Name or "Unnamed", "") for g in sorted(results, key=lambda x: x.Name or "Unnamed")]
diff --git a/src/blenderbim/blenderbim/bim/module/clash/operator.py b/src/blenderbim/blenderbim/bim/module/clash/operator.py
index 05e82c7f77..f32e7bfad3 100644
--- a/src/blenderbim/blenderbim/bim/module/clash/operator.py
+++ b/src/blenderbim/blenderbim/bim/module/clash/operator.py
@@ -86,14 +86,14 @@ class ImportClashSets(bpy.types.Operator):
new_source = new.a.add()
new_source.name = clash_source["file"]
if "selector" in clash_source:
- new_source.selector = clash_source["selector"]
+ tool.Search.import_filter_query(clash_source["selector"], new_source.filter_groups)
new_source.mode = clash_source["mode"]
if "b" in clash_set and clash_set["b"]:
for clash_source in clash_set["b"]:
new_source = new.b.add()
new_source.name = clash_source["file"]
if "selector" in clash_source:
- new_source.selector = clash_source["selector"]
+ tool.Search.import_filter_query(clash_source["selector"], new_source.filter_groups)
new_source.mode = clash_source["mode"]
tool.Clash.import_active_clashes()
return {"FINISHED"}
@@ -209,8 +209,11 @@ class ExecuteIfcClash(bpy.types.Operator):
def invoke(self, context, event):
_, extension = os.path.splitext(self.filepath)
- if extension != ".json":
- self.filepath = bpy.path.ensure_ext(bpy.data.filepath, ".bcf")
+ if extension != ".bcf":
+ self.filepath = bpy.path.ensure_ext(bpy.data.filepath, ".json")
+ # TODO Temporarily until BCF support comes back
+ # if extension != ".json":
+ # self.filepath = bpy.path.ensure_ext(bpy.data.filepath, ".bcf")
WindowManager = context.window_manager
WindowManager.fileselect_add(self)
return {"RUNNING_MODAL"}
@@ -221,6 +224,9 @@ class ExecuteIfcClash(bpy.types.Operator):
self.props = context.scene.BIMClashProperties
_, extension = os.path.splitext(self.filepath)
+ if extension != ".bcf":
+ self.filepath = bpy.path.ensure_ext(self.filepath, ".json")
+ # TODO Temporarily until BCF support comes back
if extension != ".json":
self.filepath = bpy.path.ensure_ext(self.filepath, ".bcf")
diff --git a/src/blenderbim/blenderbim/bim/module/clash/prop.py b/src/blenderbim/blenderbim/bim/module/clash/prop.py
index f6e798a3f2..0f7e7c2275 100644
--- a/src/blenderbim/blenderbim/bim/module/clash/prop.py
+++ b/src/blenderbim/blenderbim/bim/module/clash/prop.py
@@ -17,7 +17,7 @@
# along with BlenderBIM Add-on. If not, see .
import bpy
-from blenderbim.bim.prop import StrProperty, Attribute
+from blenderbim.bim.prop import StrProperty, Attribute, BIMFilterGroup
from bpy.types import PropertyGroup
from bpy.props import (
PointerProperty,
@@ -33,11 +33,12 @@ from bpy.props import (
class ClashSource(PropertyGroup):
name: StringProperty(name="File")
- selector: StringProperty(name="Selector")
+ filter_groups: CollectionProperty(type=BIMFilterGroup, name="Filter Groups")
mode: EnumProperty(
items=[
- ("i", "Include", "Only the selected objects are included for clashing"),
- ("e", "Exclude", "All objects except the selected objects are included for clashing"),
+ ("a", "All Elements", "All elements will be used for clashing"),
+ ("i", "Include", "Only the selected elements are included for clashing"),
+ ("e", "Exclude", "All elements except the selected elements are included for clashing"),
],
name="Mode",
)
diff --git a/src/blenderbim/blenderbim/bim/module/clash/ui.py b/src/blenderbim/blenderbim/bim/module/clash/ui.py
index 204ece028d..d5322a568b 100644
--- a/src/blenderbim/blenderbim/bim/module/clash/ui.py
+++ b/src/blenderbim/blenderbim/bim/module/clash/ui.py
@@ -17,7 +17,9 @@
# along with BlenderBIM Add-on. If not, see .
import bpy
+import blenderbim.bim.helper
from bpy.types import Panel
+from blenderbim.bim.module.clash.data import ClashData
class BIM_PT_ifcclash(Panel):
@@ -30,6 +32,9 @@ class BIM_PT_ifcclash(Panel):
bl_parent_id = "BIM_PT_tab_clash_detection"
def draw(self, context):
+ if not ClashData.is_loaded:
+ ClashData.load()
+
layout = self.layout
scene = context.scene
@@ -78,6 +83,7 @@ class BIM_PT_ifcclash(Panel):
for index, source in enumerate(clash_set.a):
row = layout.row(align=True)
row.prop(source, "name", text="")
+ row.prop(source, "mode", text="")
op = row.operator("bim.select_clash_source", icon="FILE_FOLDER", text="")
op.index = index
op.group = "a"
@@ -85,9 +91,10 @@ class BIM_PT_ifcclash(Panel):
op.index = index
op.group = "a"
- row = layout.row(align=True)
- row.prop(source, "mode", text="")
- row.prop(source, "selector", text="")
+ if source.mode != "a":
+ blenderbim.bim.helper.draw_filter(
+ layout, source.filter_groups, ClashData, f"clash_{props.active_clash_set_index}_a_{index}"
+ )
row = layout.row(align=True)
row.label(text="Group B:", icon="OUTLINER_OB_POINTCLOUD")
@@ -96,6 +103,7 @@ class BIM_PT_ifcclash(Panel):
for index, source in enumerate(clash_set.b):
row = layout.row(align=True)
row.prop(source, "name", text="")
+ row.prop(source, "mode", text="")
op = row.operator("bim.select_clash_source", icon="FILE_FOLDER", text="")
op.index = index
op.group = "b"
@@ -103,9 +111,10 @@ class BIM_PT_ifcclash(Panel):
op.index = index
op.group = "b"
- row = layout.row(align=True)
- row.prop(source, "mode", text="")
- row.prop(source, "selector", text="")
+ if source.mode != "a":
+ blenderbim.bim.helper.draw_filter(
+ layout, source.filter_groups, ClashData, f"clash_{props.active_clash_set_index}_b_{index}"
+ )
row = layout.row()
row.prop(props, "should_create_clash_snapshots")
diff --git a/src/blenderbim/blenderbim/tool/clash.py b/src/blenderbim/blenderbim/tool/clash.py
index 021c275851..c83c3f9deb 100644
--- a/src/blenderbim/blenderbim/tool/clash.py
+++ b/src/blenderbim/blenderbim/tool/clash.py
@@ -37,8 +37,9 @@ class Clash(blenderbim.core.tool.Clash):
for ab in ["a", "b"]:
for data in getattr(clash_set, ab):
clash_source = {"file": data.name}
- if data.selector:
- clash_source["selector"] = data.selector
+ query = tool.Search.export_filter_query(data.filter_groups)
+ if query and data.mode != "a":
+ clash_source["selector"] = query
clash_source["mode"] = data.mode
if ab == "a":
a.append(clash_source)
diff --git a/src/blenderbim/blenderbim/tool/search.py b/src/blenderbim/blenderbim/tool/search.py
index 4a3f9b3f1b..e666158720 100644
--- a/src/blenderbim/blenderbim/tool/search.py
+++ b/src/blenderbim/blenderbim/tool/search.py
@@ -26,6 +26,11 @@ class Search(blenderbim.core.tool.Search):
return bpy.context.active_object.data.BIMCameraProperties.include_filter_groups
elif module == "drawing_exclude":
return bpy.context.active_object.data.BIMCameraProperties.exclude_filter_groups
+ elif module.startswith("clash"):
+ _, clash_set_index, ab, clash_source_index = module.split("_")
+ return getattr(bpy.context.scene.BIMClashProperties.clash_sets[int(clash_set_index)], ab)[
+ int(clash_source_index)
+ ].filter_groups
@classmethod
def import_filter_query(cls, query: str, filter_groups: bpy.types.bpy_prop_collection) -> None: