mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 02:02:22 +00:00
draft
endofday 1207 240pm 14/07 draft version cleanup
This commit is contained in:
@@ -20,6 +20,7 @@ import bpy
|
||||
from . import ui, prop, operator
|
||||
|
||||
classes = (
|
||||
operator.EditBlenderCollection,
|
||||
operator.ActivateIfcClassFilter,
|
||||
operator.ActivateIfcBuildingStoreyFilter,
|
||||
operator.ColourByAttribute,
|
||||
@@ -31,18 +32,30 @@ classes = (
|
||||
operator.SelectGlobalId,
|
||||
operator.SelectIfcClass,
|
||||
operator.SelectPset,
|
||||
operator.Reset3dView,
|
||||
operator.FilterModelElements,
|
||||
prop.BIMFilterClasses,
|
||||
prop.BIMFilterBuildingStoreys,
|
||||
prop.BIMSearchProperties,
|
||||
prop.SearchCollection,
|
||||
prop.SearchQueryFilter,
|
||||
prop.SearchQuery,
|
||||
prop.SearchQueryGroup,
|
||||
prop.IfcSelectorProperties,
|
||||
ui.BIM_PT_search,
|
||||
ui.BIM_UL_ifc_class_filter,
|
||||
ui.BIM_UL_ifc_building_storey_filter,
|
||||
ui.BIM_PT_IFCSelector
|
||||
)
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.Scene.BIMSearchProperties = bpy.props.PointerProperty(type=prop.BIMSearchProperties)
|
||||
bpy.types.Scene.BIMSearchProperties = bpy.props.PointerProperty(
|
||||
type=prop.BIMSearchProperties)
|
||||
bpy.types.Scene.IfcSelectorProperties = bpy.props.PointerProperty(
|
||||
type=prop.IfcSelectorProperties)
|
||||
|
||||
|
||||
def unregister():
|
||||
del bpy.types.Scene.BIMSearchProperties
|
||||
del bpy.types.Scene.IfcSelectorProperties
|
||||
|
||||
@@ -20,6 +20,7 @@ import re
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.element
|
||||
from ifcopenshell.util.selector import Selector
|
||||
import blenderbim.tool as tool
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from itertools import cycle
|
||||
@@ -54,6 +55,23 @@ def does_keyword_exist(pattern, string, context):
|
||||
return True
|
||||
|
||||
|
||||
class EditBlenderCollection(bpy.types.Operator):
|
||||
bl_idname = "bim.edit_blender_collection"
|
||||
bl_label = "Add or Remove blender collection item"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
option: bpy.props.StringProperty()
|
||||
collection: bpy.props.StringProperty()
|
||||
index: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
if self.option == "add":
|
||||
getattr(context.bim_prop_group, self.collection).add()
|
||||
else:
|
||||
getattr(context.bim_prop_group, self.collection).remove(self.index)
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class SelectGlobalId(bpy.types.Operator):
|
||||
"""Click to select the objects that match with the given Global ID"""
|
||||
|
||||
@@ -86,7 +104,8 @@ class SelectIfcClass(bpy.types.Operator):
|
||||
for obj in context.visible_objects:
|
||||
if not obj.BIMObjectProperties.ifc_definition_id or obj.is_library_indirect:
|
||||
continue
|
||||
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
element = self.file.by_id(
|
||||
obj.BIMObjectProperties.ifc_definition_id)
|
||||
if does_keyword_exist(self.ifc_class, element.is_a(), context):
|
||||
obj.select_set(True)
|
||||
return {"FINISHED"}
|
||||
@@ -107,10 +126,12 @@ class SelectAttribute(bpy.types.Operator):
|
||||
for obj in context.visible_objects:
|
||||
if not obj.BIMObjectProperties.ifc_definition_id:
|
||||
continue
|
||||
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
element = self.file.by_id(
|
||||
obj.BIMObjectProperties.ifc_definition_id)
|
||||
if context.scene.BIMSearchProperties.should_ignorecase:
|
||||
data = element.get_info()
|
||||
value = next((v for k, v in data.items() if k.lower() == attribute_name.lower()), None)
|
||||
value = next((v for k, v in data.items()
|
||||
if k.lower() == attribute_name.lower()), None)
|
||||
else:
|
||||
value = getattr(element, attribute_name, None)
|
||||
if does_keyword_exist(pattern, value, context):
|
||||
@@ -134,7 +155,8 @@ class SelectPset(bpy.types.Operator):
|
||||
for obj in context.visible_objects:
|
||||
if not obj.BIMObjectProperties.ifc_definition_id:
|
||||
continue
|
||||
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
element = self.file.by_id(
|
||||
obj.BIMObjectProperties.ifc_definition_id)
|
||||
psets = ifcopenshell.util.element.get_psets(element)
|
||||
if search_pset_name == "":
|
||||
props = {}
|
||||
@@ -142,8 +164,10 @@ class SelectPset(bpy.types.Operator):
|
||||
else:
|
||||
props = None
|
||||
if context.scene.BIMSearchProperties.should_ignorecase:
|
||||
props = props or next((v for k, v in psets.items() if k.lower() == search_pset_name.lower()), {})
|
||||
value = str(next((v for k, v in props.items() if k.lower() == search_prop_name.lower()), None))
|
||||
props = props or next(
|
||||
(v for k, v in psets.items() if k.lower() == search_pset_name.lower()), {})
|
||||
value = str(next((v for k, v in props.items()
|
||||
if k.lower() == search_prop_name.lower()), None))
|
||||
else:
|
||||
props = props or psets.get(search_pset_name, {})
|
||||
value = props.get(search_prop_name, None)
|
||||
@@ -175,10 +199,12 @@ class ColourByAttribute(bpy.types.Operator):
|
||||
for obj in context.visible_objects:
|
||||
if not obj.BIMObjectProperties.ifc_definition_id:
|
||||
continue
|
||||
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
element = self.file.by_id(
|
||||
obj.BIMObjectProperties.ifc_definition_id)
|
||||
if context.scene.BIMSearchProperties.should_ignorecase:
|
||||
data = element.get_info()
|
||||
value = next((v for k, v in data.items() if k.lower() == attribute_name.lower()), None)
|
||||
value = next((v for k, v in data.items()
|
||||
if k.lower() == attribute_name.lower()), None)
|
||||
else:
|
||||
value = getattr(element, attribute_name, None)
|
||||
if value not in values:
|
||||
@@ -192,7 +218,8 @@ class ColourByAttribute(bpy.types.Operator):
|
||||
def store_state(self, context):
|
||||
areas = [a for a in context.screen.areas if a.type == "VIEW_3D"]
|
||||
if areas:
|
||||
self.transaction_data = {"area": areas[0], "color_type": areas[0].spaces[0].shading.color_type}
|
||||
self.transaction_data = {
|
||||
"area": areas[0], "color_type": areas[0].spaces[0].shading.color_type}
|
||||
|
||||
def rollback(self, data):
|
||||
if data:
|
||||
@@ -227,7 +254,8 @@ class ColourByPset(bpy.types.Operator):
|
||||
for obj in context.visible_objects:
|
||||
if not obj.BIMObjectProperties.ifc_definition_id:
|
||||
continue
|
||||
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
element = self.file.by_id(
|
||||
obj.BIMObjectProperties.ifc_definition_id)
|
||||
psets = ifcopenshell.util.element.get_psets(element)
|
||||
if search_pset_name == "":
|
||||
props = {}
|
||||
@@ -235,8 +263,10 @@ class ColourByPset(bpy.types.Operator):
|
||||
else:
|
||||
props = None
|
||||
if context.scene.BIMSearchProperties.should_ignorecase:
|
||||
props = props or next((v for k, v in psets.items() if k.lower() == search_pset_name.lower()), {})
|
||||
value = str(next((v for k, v in props.items() if k.lower() == search_prop_name.lower()), None))
|
||||
props = props or next(
|
||||
(v for k, v in psets.items() if k.lower() == search_pset_name.lower()), {})
|
||||
value = str(next((v for k, v in props.items()
|
||||
if k.lower() == search_prop_name.lower()), None))
|
||||
else:
|
||||
props = props or psets.get(search_pset_name, {})
|
||||
value = str(props.get(search_prop_name, None))
|
||||
@@ -251,7 +281,8 @@ class ColourByPset(bpy.types.Operator):
|
||||
def store_state(self, context):
|
||||
areas = [a for a in context.screen.areas if a.type == "VIEW_3D"]
|
||||
if areas:
|
||||
self.transaction_data = {"area": areas[0], "color_type": areas[0].spaces[0].shading.color_type}
|
||||
self.transaction_data = {
|
||||
"area": areas[0], "color_type": areas[0].spaces[0].shading.color_type}
|
||||
|
||||
def rollback(self, data):
|
||||
if data:
|
||||
@@ -284,7 +315,8 @@ class ColourByClass(bpy.types.Operator):
|
||||
for obj in context.visible_objects:
|
||||
if not obj.BIMObjectProperties.ifc_definition_id:
|
||||
continue
|
||||
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
element = self.file.by_id(
|
||||
obj.BIMObjectProperties.ifc_definition_id)
|
||||
ifc_class = element.is_a()
|
||||
if ifc_class not in ifc_classes:
|
||||
ifc_classes[ifc_class] = next(colours)
|
||||
@@ -297,7 +329,8 @@ class ColourByClass(bpy.types.Operator):
|
||||
def store_state(self, context):
|
||||
areas = [a for a in context.screen.areas if a.type == "VIEW_3D"]
|
||||
if areas:
|
||||
self.transaction_data = {"area": areas[0], "color_type": areas[0].spaces[0].shading.color_type}
|
||||
self.transaction_data = {
|
||||
"area": areas[0], "color_type": areas[0].spaces[0].shading.color_type}
|
||||
|
||||
def rollback(self, data):
|
||||
if data:
|
||||
@@ -324,7 +357,8 @@ class ToggleFilterSelection(bpy.types.Operator):
|
||||
"Click to select/deselect current selection"
|
||||
bl_idname = "bim.toggle_filter_selection"
|
||||
bl_label = "Toggle Filter Selection"
|
||||
action: bpy.props.EnumProperty(items=(("SELECT", "Select", ""), ("DESELECT", "Deselect", "")))
|
||||
action: bpy.props.EnumProperty(
|
||||
items=(("SELECT", "Select", ""), ("DESELECT", "Deselect", "")))
|
||||
|
||||
def execute(self, context):
|
||||
props = bpy.context.scene.BIMSearchProperties
|
||||
@@ -383,8 +417,10 @@ class ActivateIfcClassFilter(bpy.types.Operator):
|
||||
else len(bpy.context.scene.BIMSearchProperties.filter_classes),
|
||||
)
|
||||
row = self.layout.row(align=True)
|
||||
row.operator("bim.toggle_filter_selection", text="Select All").action = "SELECT"
|
||||
row.operator("bim.toggle_filter_selection", text="Deselect All").action = "DESELECT"
|
||||
row.operator("bim.toggle_filter_selection",
|
||||
text="Select All").action = "SELECT"
|
||||
row.operator("bim.toggle_filter_selection",
|
||||
text="Deselect All").action = "DESELECT"
|
||||
|
||||
|
||||
class ActivateIfcBuildingStoreyFilter(bpy.types.Operator):
|
||||
@@ -431,5 +467,102 @@ class ActivateIfcBuildingStoreyFilter(bpy.types.Operator):
|
||||
else len(bpy.context.scene.BIMSearchProperties.filter_building_storeys),
|
||||
)
|
||||
row = self.layout.row(align=True)
|
||||
row.operator("bim.toggle_filter_selection", text="Select All").action = "SELECT"
|
||||
row.operator("bim.toggle_filter_selection", text="Deselect All").action = "DESELECT"
|
||||
row.operator("bim.toggle_filter_selection",
|
||||
text="Select All").action = "SELECT"
|
||||
row.operator("bim.toggle_filter_selection",
|
||||
text="Deselect All").action = "DESELECT"
|
||||
|
||||
|
||||
class Reset3dView(bpy.types.Operator):
|
||||
"""Filter model elements based on selection"""
|
||||
bl_idname = "bim.reset_3d_view"
|
||||
bl_label = "Reset 3D View"
|
||||
|
||||
def execute(self, context):
|
||||
for obj in bpy.data.scenes["Scene"].objects:
|
||||
obj.hide_set(False)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class FilterModelElements(bpy.types.Operator):
|
||||
"""Filter model elements based on selection"""
|
||||
bl_idname = "bim.filter_model_elements"
|
||||
bl_label = "Filter Model Elements"
|
||||
option: bpy.props.StringProperty("select|isolate|hide")
|
||||
|
||||
def execute(self, context):
|
||||
selector = context.scene.IfcSelectorProperties
|
||||
selection = self.add_groups(selector)
|
||||
selector.selector_query_syntax = selection
|
||||
self.update_model_view(context, selection)
|
||||
return {"FINISHED"}
|
||||
|
||||
def add_groups(self, selector):
|
||||
selection = ''
|
||||
for group_index, group in enumerate(selector.groups):
|
||||
if group_index != 0:
|
||||
selection += " | "
|
||||
selection += "(" if len(selector.groups) >1 else ""
|
||||
selection = self.add_queries(selection, group)
|
||||
|
||||
selection += ")" if len(selector.groups) >1 else ""
|
||||
return selection
|
||||
|
||||
def add_queries(self, selection, group):
|
||||
for query_index, query in enumerate(group.queries):
|
||||
if query_index != 0:
|
||||
selection += " & " if query.and_or == "and" else " | "
|
||||
|
||||
if query.selector == "IFC Class":
|
||||
active_option = query.active_option.split(": ")[1]
|
||||
selection += f".{active_option}"
|
||||
selection = self.add_filters(selection, query)
|
||||
|
||||
elif query.selector == "GlobalId":
|
||||
selection += f"#{query.global_id}"
|
||||
|
||||
elif query.selector == "IfcElementType":
|
||||
index = int(query.active_sub_option.split(":")[0])
|
||||
selection += f"* #{query.sub_options[index].global_id}"
|
||||
|
||||
elif query.selector == "IfcSpatialElement":
|
||||
index = int(query.active_sub_option.split(":")[0])
|
||||
selection += f"@ #{query.sub_options[index].global_id}"
|
||||
return selection
|
||||
|
||||
def add_filters(self, selection, query):
|
||||
for f_index, f in enumerate(query.filters):
|
||||
|
||||
if f_index !=0:
|
||||
selection += " & " if f.and_or == "and" else " | "
|
||||
selection += f".{query.active_option}"
|
||||
|
||||
selection += "["
|
||||
|
||||
if f.selector == "Pset-Property":
|
||||
selection += f'{f.active_option}.{f.active_sub_option} {"!" if f.negation else ""} ="{f.value}"'
|
||||
elif f.selector == "Attribute":
|
||||
selection += f'{f.attribute} {"!" if f.negation else ""}= "{f.value}"'
|
||||
|
||||
selection += "]"
|
||||
return selection
|
||||
|
||||
def update_model_view(self, context, selection):
|
||||
query = Selector.parse(IfcStore.file, selection)
|
||||
sel_element_ids = [e.id() for e in query]
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
|
||||
|
||||
for obj in bpy.data.scenes["Scene"].objects:
|
||||
obj.hide_set(False) # reset 3d view
|
||||
|
||||
if self.option == "select":
|
||||
if obj.BIMObjectProperties.ifc_definition_id in sel_element_ids:
|
||||
obj.select_set(True)
|
||||
elif self.option == "isolate":
|
||||
if obj.BIMObjectProperties.ifc_definition_id not in sel_element_ids:
|
||||
obj.hide_set(True)
|
||||
elif self.option == "hide":
|
||||
if obj.BIMObjectProperties.ifc_definition_id in sel_element_ids:
|
||||
obj.hide_set(True)
|
||||
|
||||
|
||||
@@ -16,10 +16,13 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy
|
||||
from ifcopenshell import util
|
||||
from ifcopenshell.util.selector import Selector
|
||||
import blenderbim.tool as tool
|
||||
from blenderbim.bim.prop import ObjProperty
|
||||
from blenderbim.bim.prop import ObjProperty, StrProperty
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from bpy.types import PropertyGroup
|
||||
from blenderbim.tool.ifc import Ifc
|
||||
from . import ui, prop, operator
|
||||
from bpy.props import (
|
||||
PointerProperty,
|
||||
@@ -90,3 +93,149 @@ class BIMSearchProperties(PropertyGroup):
|
||||
filter_classes_index: IntProperty(name="Filter Classes Index")
|
||||
filter_building_storeys: CollectionProperty(type=BIMFilterBuildingStoreys, name="Filter Level")
|
||||
filter_building_storeys_index: IntProperty(name="Filter Level Index")
|
||||
|
||||
|
||||
def get_classes(self, ifc_product):
|
||||
declaration = tool.Ifc.schema().declaration_by_name(ifc_product)
|
||||
declarations = util.schema.get_subtypes(declaration)
|
||||
names = [d.name() for d in declarations]
|
||||
return [(c, c, "") for c in sorted(names)]
|
||||
|
||||
|
||||
def load_sub_options(self, context):
|
||||
if self.selector not in ["IfcClass"]:
|
||||
self.load_option = "sub_options"
|
||||
load_selection_options(self, context)
|
||||
|
||||
def load_selection_options(self, context):
|
||||
ifc = IfcStore.file
|
||||
load_option = self.load_option
|
||||
op = getattr(self, load_option)
|
||||
op.clear()
|
||||
|
||||
options = []
|
||||
|
||||
if load_option == "options":
|
||||
self.sub_options.clear()
|
||||
if self.selector == "IFC Class":
|
||||
options = get_classes(self, "IfcElement")
|
||||
options.append(("IfcSpace", "IfcSpace",""))
|
||||
elif self.selector == "IfcSpatialElement":
|
||||
options = get_classes(self, "IfcSpatialElement")
|
||||
elif self.selector == "IfcElementType":
|
||||
options = get_classes(self, "IfcElementType")
|
||||
elif self.selector == "GlobalId":
|
||||
return
|
||||
elif self.selector == "IfcPropertySet":
|
||||
psets = Selector.parse(ifc, ".IfcPropertySet")
|
||||
options = set([o.Name for o in psets])
|
||||
|
||||
elif load_option == "sub_options":
|
||||
if self.selector in ["IfcSpatialElement", "IfcElementType"]:
|
||||
active_option = self.active_option.split(": ")[1]
|
||||
options = Selector.parse(ifc, f".{active_option}")
|
||||
|
||||
elif self.selector == "IfcPropertySet":
|
||||
options = set()
|
||||
active_pset = self.active_option.split(": ")[1]
|
||||
psets_in_file = Selector.parse(ifc, f'.IfcPropertySet[Name="{active_pset}"]')
|
||||
for pset in psets_in_file:
|
||||
for prop in pset.HasProperties:
|
||||
options.add(prop.Name)
|
||||
|
||||
|
||||
for index, option in enumerate(options):
|
||||
new = op.add()
|
||||
if self.selector in ["IfcSpatialElement", "IfcElementType"]:
|
||||
if self.load_option == "sub_options":
|
||||
new.name = f"{index}: {option.Name}"
|
||||
new.global_id = option.GlobalId
|
||||
else:
|
||||
new.name = f"{index}: {option[0]}"
|
||||
elif self.selector == "IfcPropertySet":
|
||||
new.name = f"{index}: {option}"
|
||||
else:
|
||||
new.name = f"{index}: {option[0]}"
|
||||
|
||||
self.load_option = "options"
|
||||
|
||||
|
||||
def load_spatial_elements(self, context):
|
||||
ifc = IfcStore.file
|
||||
col_items = Selector.parse(ifc, f".{self.selected_spatial_element}")
|
||||
collection = getattr(self, "sub_spatial_elements", None)
|
||||
collection.clear()
|
||||
for index, c in enumerate(col_items):
|
||||
new = collection.add()
|
||||
new.name = f"{index}-{c.Name}"
|
||||
|
||||
|
||||
class SearchCollection(PropertyGroup):
|
||||
name: StringProperty()
|
||||
long_name: StringProperty()
|
||||
global_id: StringProperty()
|
||||
|
||||
class IfcSelector:
|
||||
and_or: EnumProperty(
|
||||
items=[(i, i, i) for i in ["and", "or"]],
|
||||
)
|
||||
negation: BoolProperty(name="not")
|
||||
comparison: EnumProperty(
|
||||
items=[
|
||||
("=", "equal to", ""),
|
||||
("*=", "contains", ""),
|
||||
(">=", "greater than or equal to", ""),
|
||||
("<=", "lesser than or equal to", ""),
|
||||
(">", "greater than", ""),
|
||||
("<", "less than", ""),
|
||||
],
|
||||
)
|
||||
load_option: StringProperty(default="options")
|
||||
|
||||
options: CollectionProperty(type=SearchCollection)
|
||||
active_option: StringProperty(update=load_sub_options)
|
||||
|
||||
sub_options: CollectionProperty(type=SearchCollection)
|
||||
active_sub_option: StringProperty()
|
||||
|
||||
value: StringProperty()
|
||||
|
||||
|
||||
class SearchQueryFilter(PropertyGroup, IfcSelector):
|
||||
selector: EnumProperty(
|
||||
items=[(i, i, i) for i in ["-", "IfcPropertySet", "Attribute"]],
|
||||
name="Filter selection by",
|
||||
update=load_selection_options,
|
||||
default="-",
|
||||
)
|
||||
attribute: EnumProperty(
|
||||
items=[(i, i, i) for i in ["GlobalId", "Name", "Description", "ObjectType", "Tag", "PredefinedType"]],
|
||||
name="Filter selection by",
|
||||
update=load_selection_options,
|
||||
)
|
||||
|
||||
# property_sets: CollectionProperty(type=StrProperty)
|
||||
# selected_property_set: StringProperty(update=load_selection_options)
|
||||
|
||||
# prop_names: CollectionProperty(type=StrProperty)
|
||||
# selected_prop: StringProperty()
|
||||
# prop_value: StringProperty()
|
||||
|
||||
class SearchQuery(PropertyGroup, IfcSelector):
|
||||
filters: CollectionProperty(type=SearchQueryFilter)
|
||||
selector: EnumProperty(
|
||||
items=[(i, i, i) for i in ["-", "IFC Class", "IfcSpatialElement", "IfcElementType", "GlobalId"]],
|
||||
name="Selector type",
|
||||
update=load_selection_options,
|
||||
default="-",
|
||||
)
|
||||
|
||||
class SearchQueryGroup(PropertyGroup, IfcSelector):
|
||||
queries: CollectionProperty(type=SearchQuery)
|
||||
|
||||
|
||||
class IfcSelectorProperties(PropertyGroup, IfcSelector):
|
||||
groups: CollectionProperty(type=SearchQueryGroup)
|
||||
selector_query_syntax: StringProperty()
|
||||
|
||||
|
||||
|
||||
@@ -102,3 +102,136 @@ class BIM_UL_ifc_building_storey_filter(bpy.types.UIList):
|
||||
split = split.column()
|
||||
split.scale_x = 0.5
|
||||
split.label(text=str(item.total))
|
||||
|
||||
|
||||
class BIM_PT_IFCSelector(Panel):
|
||||
bl_label = "IFC Selector"
|
||||
bl_idname = "BIM_PT_ifc_selector"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
bl_parent_id = "BIM_PT_collaboration"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return IfcStore.get_file()
|
||||
|
||||
def draw(self, context):
|
||||
ifc_selector = context.scene.IfcSelectorProperties
|
||||
layout = self.layout
|
||||
row = layout.row()
|
||||
|
||||
row.context_pointer_set(name="bim_prop_group", data=ifc_selector)
|
||||
op = row.operator("bim.edit_blender_collection", text="Add selection group")
|
||||
op.option = "add"
|
||||
op.collection = "groups"
|
||||
layout.separator()
|
||||
|
||||
self.draw_query_group_ui(ifc_selector, layout)
|
||||
|
||||
if len(ifc_selector.groups) != 0:
|
||||
row = layout.row()
|
||||
row.alignment = "CENTER"
|
||||
select = row.operator("bim.filter_model_elements", text="select")
|
||||
select.option = "select"
|
||||
isolate = row.operator("bim.filter_model_elements", text="isolate")
|
||||
isolate.option = "isolate"
|
||||
hide = row.operator("bim.filter_model_elements", text="hide")
|
||||
hide.option = "hide"
|
||||
reset = row.operator("bim.reset_3d_view", text="reset 3d view")
|
||||
|
||||
row = layout.row()
|
||||
row.prop(ifc_selector, "selector_query_syntax", text="Query Syntax")
|
||||
|
||||
def draw_query_group_ui(self, ifc_selector, layout):
|
||||
for index, group in enumerate(ifc_selector.groups):
|
||||
row = layout.row()
|
||||
row.alignment = "CENTER"
|
||||
row.label(text="or") if index !=0 else None
|
||||
|
||||
box = layout.box()
|
||||
row = box.row(align=True)
|
||||
row.alignment = "CENTER"
|
||||
row.label(text=f"Group #{str(index+1)}")
|
||||
row.context_pointer_set(name="bim_prop_group", data=group)
|
||||
op = row.operator("bim.edit_blender_collection", text="Add query", icon="PLUS")
|
||||
op.option = "add"
|
||||
op.collection = "queries"
|
||||
|
||||
row.context_pointer_set(name="bim_prop_group", data=ifc_selector)
|
||||
op = row.operator("bim.edit_blender_collection", text="Remove selection group")
|
||||
op.option = "remove"
|
||||
op.collection = "groups"
|
||||
op.index = index
|
||||
|
||||
self.draw_query_ui(group, box)
|
||||
|
||||
def draw_query_ui(self, group, box):
|
||||
for index, query in enumerate(group.queries):
|
||||
row = box.row()
|
||||
row.alignment = "LEFT"
|
||||
|
||||
row.prop(query, "and_or", text="") if index != 0 else None
|
||||
if query.and_or == "or":
|
||||
row=box.row()
|
||||
row.alignment = "LEFT"
|
||||
row.prop(query, "selector", text="")
|
||||
|
||||
if query.selector in ["IFC Class", "IfcSpatialElement", "IfcElementType"]:
|
||||
row.label(text="Equals")
|
||||
row.prop_search(query, "active_option", query, "options", text="")
|
||||
row.prop_search(query, "active_sub_option", query, "sub_options", text="") if len(query.sub_options) != 0 else None
|
||||
self.draw_filter_ui(index, box, query)
|
||||
|
||||
elif query.selector in ["GlobalId", "Attribute"]:
|
||||
row.prop(query, "negation", text="")
|
||||
row.prop(query, "comparison", text="")
|
||||
row.prop(query, "value", text="")
|
||||
|
||||
row.context_pointer_set(name="bim_prop_group", data=group)
|
||||
op = row.operator("bim.edit_blender_collection", icon="REMOVE", text="")
|
||||
op.option = "remove"
|
||||
op.collection = "queries"
|
||||
op.index = index
|
||||
|
||||
row.context_pointer_set(name="bim_prop_group", data=query)
|
||||
op = (
|
||||
row.operator("bim.edit_blender_collection", text="Add filter")
|
||||
if query.selector == "IFC Class"
|
||||
else None
|
||||
)
|
||||
if op:
|
||||
op.option = "add"
|
||||
op.collection = "filters"
|
||||
|
||||
def draw_filter_ui(self, index, box, query):
|
||||
for filter_index, f in enumerate(query.filters):
|
||||
row = box.row()
|
||||
row.alignment = "LEFT"
|
||||
row.label(text=" ↪")
|
||||
row.prop(f, "and_or", text="") if filter_index != 0 else None
|
||||
if f.and_or == "or":
|
||||
row=box.row()
|
||||
row.alignment = "LEFT"
|
||||
row.label(text=" ↪")
|
||||
row.prop(f, "selector", text="")
|
||||
|
||||
if f.selector == "Attribute":
|
||||
row.prop(f, "attribute", text="")
|
||||
row.prop(f, "negation",)
|
||||
row.prop(f, "comparison", text="")
|
||||
row.prop(f, "value", text="")
|
||||
|
||||
elif f.selector == "IfcPropertySet":
|
||||
row.prop_search(f, "active_option", f, "options", text="")
|
||||
row.prop_search(f, "active_sub_option", f, "sub_options", text="")
|
||||
row.prop(f, "negation")
|
||||
row.prop(f, "comparison", text="")
|
||||
row.prop(f, "value", text="")
|
||||
|
||||
row.context_pointer_set(name="bim_prop_group", data=query)
|
||||
op = row.operator("bim.edit_blender_collection", icon="REMOVE", text="")
|
||||
op.option = "remove"
|
||||
op.collection = "filters"
|
||||
op.index = filter_index
|
||||
|
||||
@@ -21,13 +21,11 @@ import ifcopenshell.util.fm
|
||||
import ifcopenshell.util.element
|
||||
import lark
|
||||
|
||||
|
||||
class Selector:
|
||||
@classmethod
|
||||
def parse(cls, ifc_file, query, elements=None):
|
||||
cls.file = ifc_file
|
||||
cls.elements = elements
|
||||
|
||||
l = lark.Lark(
|
||||
"""start: query (lfunction query)*
|
||||
query: selector | group
|
||||
@@ -38,7 +36,7 @@ class Selector:
|
||||
filter: "[" filter_key (comparison filter_value)? "]"
|
||||
filter_key: WORD | pset_or_qto
|
||||
filter_value: ESCAPED_STRING | SIGNED_FLOAT | SIGNED_INT | BOOLEAN | NULL
|
||||
pset_or_qto: /[A-Za-z0-9_]+/ "." /[A-Za-z0-9_]+/
|
||||
pset_or_qto: /[^.= ][^.=]*[^.= ]/ "." /[^.= ][^.=]*[^.= ](?= +\W+")/
|
||||
lfunction: and | or
|
||||
inverse_relationship: types | decomposed_by | bounded_by
|
||||
types: "*"
|
||||
@@ -143,7 +141,8 @@ class Selector:
|
||||
elif hasattr(element, "ObjectTypeOf") and element.ObjectTypeOf:
|
||||
results.extend(element.ObjectTypeOf[0].RelatedObjects)
|
||||
elif inverse_relationship == "decomposed_by":
|
||||
results.extend(ifcopenshell.util.element.get_decomposition(element))
|
||||
results.extend(
|
||||
ifcopenshell.util.element.get_decomposition(element))
|
||||
elif inverse_relationship == "bounded_by" and hasattr(element, "BoundedBy"):
|
||||
for relationship in element.BoundedBy:
|
||||
results.append(relationship.RelatedBuildingElement)
|
||||
@@ -161,7 +160,8 @@ class Selector:
|
||||
if cls.elements is None:
|
||||
elements = cls.file.by_type(class_selector.children[0])
|
||||
else:
|
||||
elements = [e for e in cls.elements if e.is_a(class_selector.children[0])]
|
||||
elements = [e for e in cls.elements if e.is_a(
|
||||
class_selector.children[0])]
|
||||
if len(class_selector.children) > 1 and class_selector.children[1].data == "filter":
|
||||
return cls.filter_elements(elements, class_selector.children[1])
|
||||
return elements
|
||||
@@ -210,7 +210,8 @@ class Selector:
|
||||
key = ".".join(key.split(".")[1:])
|
||||
elif "." in key and key.split(".")[0] == "material":
|
||||
try:
|
||||
element = ifcopenshell.util.element.get_material(element, should_skip_usage=True)
|
||||
element = ifcopenshell.util.element.get_material(
|
||||
element, should_skip_usage=True)
|
||||
if not element:
|
||||
return None
|
||||
except:
|
||||
|
||||
Reference in New Issue
Block a user