mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-23 18:16:20 +00:00
Selector: added new tests and improved UX
Selector: added tests to check non-standard characters and missing values
This commit is contained in:
@@ -38,6 +38,7 @@ classes = (
|
|||||||
operator.SaveSelectorQuery,
|
operator.SaveSelectorQuery,
|
||||||
operator.OpenQueryLibrary,
|
operator.OpenQueryLibrary,
|
||||||
operator.LoadQuery,
|
operator.LoadQuery,
|
||||||
|
operator.AddToIfcGroup,
|
||||||
prop.BIMFilterClasses,
|
prop.BIMFilterClasses,
|
||||||
prop.BIMFilterBuildingStoreys,
|
prop.BIMFilterBuildingStoreys,
|
||||||
prop.BIMSearchProperties,
|
prop.BIMSearchProperties,
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import re
|
|||||||
import bpy
|
import bpy
|
||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
import ifcopenshell.util.element
|
import ifcopenshell.util.element
|
||||||
|
from ifcopenshell.api.group.data import Data
|
||||||
from ifcopenshell.util.selector import Selector
|
from ifcopenshell.util.selector import Selector
|
||||||
import blenderbim.tool as tool
|
import blenderbim.tool as tool
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
@@ -65,6 +66,13 @@ def does_keyword_exist(pattern, string, context):
|
|||||||
elif string == pattern:
|
elif string == pattern:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
# hack to close popup
|
||||||
|
# https://blender.stackexchange.com/a/202576/130742
|
||||||
|
def close_operator_panel(event):
|
||||||
|
x, y = event.mouse_x, event.mouse_y
|
||||||
|
bpy.context.window.cursor_warp(10, 10)
|
||||||
|
move_back = lambda: bpy.context.window.cursor_warp(x, y)
|
||||||
|
bpy.app.timers.register(move_back, first_interval=0.01)
|
||||||
|
|
||||||
class EditBlenderCollection(Operator):
|
class EditBlenderCollection(Operator):
|
||||||
bl_idname = "bim.edit_blender_collection"
|
bl_idname = "bim.edit_blender_collection"
|
||||||
@@ -513,7 +521,7 @@ class FilterModelElements(Operator):
|
|||||||
selection = self.add_filters(selection, query)
|
selection = self.add_filters(selection, query)
|
||||||
|
|
||||||
elif query.selector == "GlobalId":
|
elif query.selector == "GlobalId":
|
||||||
selection += f"#{query.global_id}"
|
selection += f"#{query.value}"
|
||||||
|
|
||||||
elif query.selector == "IfcElementType":
|
elif query.selector == "IfcElementType":
|
||||||
index = int(query.active_sub_option.split(":")[0])
|
index = int(query.active_sub_option.split(":")[0])
|
||||||
@@ -562,7 +570,6 @@ class FilterModelElements(Operator):
|
|||||||
|
|
||||||
class IfcSelector(Operator):
|
class IfcSelector(Operator):
|
||||||
"""Select elements in model with IFC Selector"""
|
"""Select elements in model with IFC Selector"""
|
||||||
|
|
||||||
bl_idname = "bim.ifc_selector"
|
bl_idname = "bim.ifc_selector"
|
||||||
bl_label = "Select elements with IFC Selector"
|
bl_label = "Select elements with IFC Selector"
|
||||||
|
|
||||||
@@ -603,19 +610,11 @@ class SaveSelectorQuery(Operator):
|
|||||||
|
|
||||||
class OpenQueryLibrary(Operator):
|
class OpenQueryLibrary(Operator):
|
||||||
"""Open Query Library"""
|
"""Open Query Library"""
|
||||||
|
|
||||||
bl_idname = "bim.open_query_library"
|
bl_idname = "bim.open_query_library"
|
||||||
bl_label = "Open Query Library"
|
bl_label = "Open Query Library"
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
return context.window_manager.invoke_props_dialog(self, width=400)
|
return context.window_manager.invoke_popup(self, width=400)
|
||||||
|
|
||||||
def close_panel(event):
|
|
||||||
x, y = event.mouse_x, event.mouse_y
|
|
||||||
bpy.context.window.cursor_warp(10, 10)
|
|
||||||
|
|
||||||
move_back = lambda: bpy.context.window.cursor_warp(x, y)
|
|
||||||
bpy.app.timers.register(move_back, first_interval=0.001)
|
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
@@ -642,7 +641,37 @@ class LoadQuery(Operator):
|
|||||||
bl_label = "Load Query"
|
bl_label = "Load Query"
|
||||||
index: IntProperty()
|
index: IntProperty()
|
||||||
|
|
||||||
|
def invoke(self, context, event):
|
||||||
|
close_operator_panel(event)
|
||||||
|
return self.execute(context)
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
ifc_selector = context.scene.IfcSelectorProperties
|
ifc_selector = context.scene.IfcSelectorProperties
|
||||||
ifc_selector.selector_query_syntax = ifc_selector.query_library[self.index].query
|
ifc_selector.selector_query_syntax = ifc_selector.query_library[self.index].query
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
class AddToIfcGroup(Operator):
|
||||||
|
bl_idname = "bim.add_to_ifc_group"
|
||||||
|
bl_label = "Add to IFC Group"
|
||||||
|
group_name: StringProperty(name="Group Name")
|
||||||
|
|
||||||
|
def invoke(self, context, event):
|
||||||
|
return context.window_manager.invoke_props_dialog(self, width=400)
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
layout.prop(self, "group_name")
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
self.file = IfcStore.get_file()
|
||||||
|
ifc_selector = context.scene.IfcSelectorProperties
|
||||||
|
selector_query_syntax = ifc_selector.selector_query_syntax
|
||||||
|
|
||||||
|
group = ifcopenshell.api.run("group.add_group", self.file, **{"Name": self.group_name})
|
||||||
|
objects = Selector.parse(self.file, selector_query_syntax)
|
||||||
|
for obj in objects:
|
||||||
|
ifcopenshell.api.run("group.assign_group", self.file, **{"product": obj, "group": group})
|
||||||
|
|
||||||
|
Data.load(IfcStore.get_file())
|
||||||
|
|
||||||
|
return {"FINISHED"}
|
||||||
|
|||||||
@@ -153,7 +153,8 @@ class IfcSelectorUI:
|
|||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
row.alignment = "CENTER"
|
row.alignment = "CENTER"
|
||||||
row.operator("bim.save_selector_query", text="Save Query")
|
row.operator("bim.save_selector_query", text="Save Query")
|
||||||
row.operator("bim.open_query_library", text="Load Query")
|
op = row.operator("bim.open_query_library", text="Load Query")
|
||||||
|
row.operator("bim.add_to_ifc_group", text="Add to IFC Group")
|
||||||
|
|
||||||
def draw_query_group_ui(self, ifc_selector, layout):
|
def draw_query_group_ui(self, ifc_selector, layout):
|
||||||
for index, group in enumerate(ifc_selector.groups):
|
for index, group in enumerate(ifc_selector.groups):
|
||||||
|
|||||||
@@ -23,7 +23,9 @@ import ifcopenshell.api
|
|||||||
class Usecase:
|
class Usecase:
|
||||||
def __init__(self, file, **settings):
|
def __init__(self, file, **settings):
|
||||||
self.file = file
|
self.file = file
|
||||||
self.settings = {}
|
self.settings = {
|
||||||
|
"Name": "Unnamed"
|
||||||
|
}
|
||||||
for key, value in settings.items():
|
for key, value in settings.items():
|
||||||
self.settings[key] = value
|
self.settings[key] = value
|
||||||
|
|
||||||
@@ -33,6 +35,6 @@ class Usecase:
|
|||||||
**{
|
**{
|
||||||
"GlobalId": ifcopenshell.guid.new(),
|
"GlobalId": ifcopenshell.guid.new(),
|
||||||
"OwnerHistory": ifcopenshell.api.run("owner.create_owner_history", self.file),
|
"OwnerHistory": ifcopenshell.api.run("owner.create_owner_history", self.file),
|
||||||
"Name": "Unnamed",
|
"Name": self.settings["Name"],
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ class Selector:
|
|||||||
value = None
|
value = None
|
||||||
for element in elements:
|
for element in elements:
|
||||||
element_value = cls.get_element_value(element, key)
|
element_value = cls.get_element_value(element, key)
|
||||||
if element_value is None and value is not None:
|
if element_value is None and value is not None and "not" not in comparison:
|
||||||
continue
|
continue
|
||||||
if comparison and cls.filter_element(element, element_value, comparison, value):
|
if comparison and cls.filter_element(element, element_value, comparison, value):
|
||||||
results.append(element)
|
results.append(element)
|
||||||
|
|||||||
@@ -112,6 +112,27 @@ class TestSelector(test.bootstrap.IFC4):
|
|||||||
assert subject.Selector.parse(self.file, '.IfcElement[Name*="oba"]') == [element]
|
assert subject.Selector.parse(self.file, '.IfcElement[Name*="oba"]') == [element]
|
||||||
assert subject.Selector.parse(self.file, '.IfcElement[Name*="abc"]') == []
|
assert subject.Selector.parse(self.file, '.IfcElement[Name*="abc"]') == []
|
||||||
|
|
||||||
|
def test_selecting_if_value_not_matching(self):
|
||||||
|
element_1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||||
|
element_2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||||
|
pset_1 = ifcopenshell.api.run("pset.add_pset", self.file, product=element_1, name="Foo_Bar")
|
||||||
|
pset_2 = ifcopenshell.api.run("pset.add_pset", self.file, product=element_2, name="Foo_Bar")
|
||||||
|
ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset_1, properties={"Foo": "Bar"})
|
||||||
|
ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset_2, properties={"Foo": "BOO"})
|
||||||
|
assert subject.Selector.parse(self.file, '.IfcElement[Foo_Bar.Foo != "Bar"]') == [element_2]
|
||||||
|
assert subject.Selector.parse(self.file, '.IfcElement[Foo_Bar.Foo != "BOO"]') == [element_1]
|
||||||
|
|
||||||
|
|
||||||
|
def test_selecting_when_attribute_is_none(self):
|
||||||
|
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||||
|
assert subject.Selector.parse(self.file, '.IfcElement[PredefinedType !="non-existent predefined type"]') == [element]
|
||||||
|
|
||||||
|
def test_selecting_a_property_which_includes_non_standard_characters(self):
|
||||||
|
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||||
|
pset = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name="a !%$§&/()?|*-+,€~#@µ^°a")
|
||||||
|
ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"a !%$§&/()?|*-+,€~#@µ^°a": "Bar"})
|
||||||
|
assert subject.Selector.parse(self.file, '.IfcElement[a !%$§&/()?|*-+,€~#@µ^°a.a !%$§&/()?|*-+,€~#@µ^°a="Bar"]') == [element]
|
||||||
|
|
||||||
def test_comparing_if_value_is_in_a_list(self):
|
def test_comparing_if_value_is_in_a_list(self):
|
||||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||||
element.Name = "Foobar"
|
element.Name = "Foobar"
|
||||||
|
|||||||
Reference in New Issue
Block a user