2021-01-23 14:17:50 +11:00
|
|
|
import re
|
|
|
|
|
import bpy
|
|
|
|
|
import ifcopenshell
|
|
|
|
|
import ifcopenshell.util.element
|
|
|
|
|
from blenderbim.bim.ifc import IfcStore
|
|
|
|
|
from itertools import cycle
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
colour_list = [
|
|
|
|
|
(0.651, 0.81, 0.892, 1),
|
|
|
|
|
(0.121, 0.471, 0.706, 1),
|
|
|
|
|
(0.699, 0.876, 0.54, 1),
|
|
|
|
|
(0.199, 0.629, 0.174, 1),
|
|
|
|
|
(0.983, 0.605, 0.602, 1),
|
|
|
|
|
(0.89, 0.101, 0.112, 1),
|
|
|
|
|
(0.989, 0.751, 0.427, 1),
|
|
|
|
|
(0.986, 0.497, 0.1, 1),
|
|
|
|
|
(0.792, 0.699, 0.839, 1),
|
|
|
|
|
(0.414, 0.239, 0.603, 1),
|
|
|
|
|
(0.993, 0.999, 0.6, 1),
|
|
|
|
|
(0.693, 0.349, 0.157, 1),
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
2021-07-29 23:08:17 +02:00
|
|
|
def does_keyword_exist(pattern, string, context):
|
2021-01-23 14:17:50 +11:00
|
|
|
string = str(string)
|
2021-07-29 23:08:17 +02:00
|
|
|
props = context.scene.BIMSearchProperties
|
2021-01-23 14:17:50 +11:00
|
|
|
if (
|
2021-07-29 23:08:17 +02:00
|
|
|
props.should_use_regex
|
|
|
|
|
and props.should_ignorecase
|
2021-01-23 14:17:50 +11:00
|
|
|
and re.search(pattern, string, flags=re.IGNORECASE)
|
|
|
|
|
):
|
|
|
|
|
return True
|
2021-07-29 23:08:17 +02:00
|
|
|
elif props.should_use_regex and re.search(pattern, string):
|
2021-01-23 14:17:50 +11:00
|
|
|
return True
|
2021-07-29 23:08:17 +02:00
|
|
|
elif props.should_ignorecase and string.lower() == pattern.lower():
|
2021-01-23 14:17:50 +11:00
|
|
|
return True
|
|
|
|
|
elif string == pattern:
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SelectGlobalId(bpy.types.Operator):
|
2021-08-01 17:33:55 +08:00
|
|
|
"""Click to select the objects that match with the given Global ID"""
|
2021-01-23 14:17:50 +11:00
|
|
|
bl_idname = "bim.select_global_id"
|
|
|
|
|
bl_label = "Select GlobalId"
|
2021-07-06 12:19:45 +02:00
|
|
|
bl_options = {"REGISTER", "UNDO"}
|
2021-03-25 20:29:37 +11:00
|
|
|
global_id: bpy.props.StringProperty()
|
2021-01-23 14:17:50 +11:00
|
|
|
|
|
|
|
|
def execute(self, context):
|
|
|
|
|
self.file = IfcStore.get_file()
|
|
|
|
|
props = context.scene.BIMSearchProperties
|
2021-03-25 20:29:37 +11:00
|
|
|
global_id = self.global_id or props.global_id
|
2021-01-23 14:17:50 +11:00
|
|
|
for obj in context.visible_objects:
|
|
|
|
|
if not obj.BIMObjectProperties.ifc_definition_id:
|
|
|
|
|
continue
|
|
|
|
|
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
2021-03-25 20:29:37 +11:00
|
|
|
if element.GlobalId == global_id:
|
2021-01-23 14:17:50 +11:00
|
|
|
obj.select_set(True)
|
|
|
|
|
break
|
|
|
|
|
return {"FINISHED"}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SelectIfcClass(bpy.types.Operator):
|
2021-08-01 17:33:55 +08:00
|
|
|
"""Click to select all objects that match with the given IFC class"""
|
2021-01-23 14:17:50 +11:00
|
|
|
bl_idname = "bim.select_ifc_class"
|
|
|
|
|
bl_label = "Select IFC Class"
|
2021-07-06 12:19:45 +02:00
|
|
|
bl_options = {"REGISTER", "UNDO"}
|
2021-07-19 19:19:12 +10:00
|
|
|
ifc_class: bpy.props.StringProperty()
|
2021-01-23 14:17:50 +11:00
|
|
|
|
|
|
|
|
def execute(self, context):
|
|
|
|
|
self.file = IfcStore.get_file()
|
|
|
|
|
for obj in context.visible_objects:
|
|
|
|
|
if not obj.BIMObjectProperties.ifc_definition_id:
|
|
|
|
|
continue
|
|
|
|
|
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
2021-07-29 23:08:17 +02:00
|
|
|
if does_keyword_exist(self.ifc_class, element.is_a(), context):
|
2021-01-23 14:17:50 +11:00
|
|
|
obj.select_set(True)
|
|
|
|
|
return {"FINISHED"}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SelectAttribute(bpy.types.Operator):
|
2021-08-01 17:33:55 +08:00
|
|
|
"""Click to select all objects that match with the given Attribute Name and Value"""
|
2021-01-23 14:17:50 +11:00
|
|
|
bl_idname = "bim.select_attribute"
|
|
|
|
|
bl_label = "Select Attribute"
|
2021-07-06 12:19:45 +02:00
|
|
|
bl_options = {"REGISTER", "UNDO"}
|
2021-01-23 14:17:50 +11:00
|
|
|
|
|
|
|
|
def execute(self, context):
|
|
|
|
|
self.file = IfcStore.get_file()
|
|
|
|
|
props = context.scene.BIMSearchProperties
|
|
|
|
|
pattern = props.search_attribute_value
|
|
|
|
|
attribute_name = props.search_attribute_name
|
|
|
|
|
for obj in context.visible_objects:
|
|
|
|
|
if not obj.BIMObjectProperties.ifc_definition_id:
|
|
|
|
|
continue
|
|
|
|
|
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
2021-03-08 16:42:47 +11:00
|
|
|
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)
|
|
|
|
|
else:
|
|
|
|
|
value = getattr(element, attribute_name, None)
|
2021-07-29 23:08:17 +02:00
|
|
|
if does_keyword_exist(pattern, value, context):
|
2021-01-23 14:17:50 +11:00
|
|
|
obj.select_set(True)
|
|
|
|
|
return {"FINISHED"}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SelectPset(bpy.types.Operator):
|
2021-08-01 17:33:55 +08:00
|
|
|
"""Click to select all objects that match with the given Pset Name, Properties Name and Value"""
|
2021-01-23 14:17:50 +11:00
|
|
|
bl_idname = "bim.select_pset"
|
|
|
|
|
bl_label = "Select Pset"
|
2021-07-06 12:19:45 +02:00
|
|
|
bl_options = {"REGISTER", "UNDO"}
|
2021-01-23 14:17:50 +11:00
|
|
|
|
|
|
|
|
def execute(self, context):
|
|
|
|
|
self.file = IfcStore.get_file()
|
|
|
|
|
props = context.scene.BIMSearchProperties
|
|
|
|
|
search_pset_name = props.search_pset_name
|
|
|
|
|
search_prop_name = props.search_prop_name
|
|
|
|
|
pattern = props.search_pset_value
|
|
|
|
|
for obj in context.visible_objects:
|
|
|
|
|
if not obj.BIMObjectProperties.ifc_definition_id:
|
|
|
|
|
continue
|
|
|
|
|
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
|
|
|
|
psets = ifcopenshell.util.element.get_psets(element)
|
2021-06-06 20:55:25 +10:00
|
|
|
if search_pset_name == "":
|
|
|
|
|
props = {}
|
|
|
|
|
[props.update(p) for p in psets.values()]
|
|
|
|
|
else:
|
|
|
|
|
props = None
|
2021-03-08 16:42:47 +11:00
|
|
|
if context.scene.BIMSearchProperties.should_ignorecase:
|
2021-06-06 20:55:25 +10:00
|
|
|
props = props or next((v for k, v in psets.items() if k.lower() == search_pset_name.lower()), {})
|
2021-03-08 16:42:47 +11:00
|
|
|
value = str(next((v for k, v in props.items() if k.lower() == search_prop_name.lower()), None))
|
|
|
|
|
else:
|
2021-06-06 20:55:25 +10:00
|
|
|
props = props or psets.get(search_pset_name, {})
|
2021-03-08 16:42:47 +11:00
|
|
|
value = props.get(search_prop_name, None)
|
2021-07-29 23:08:17 +02:00
|
|
|
if does_keyword_exist(pattern, value, context):
|
2021-01-23 14:17:50 +11:00
|
|
|
obj.select_set(True)
|
|
|
|
|
return {"FINISHED"}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ColourByAttribute(bpy.types.Operator):
|
2021-08-01 17:33:55 +08:00
|
|
|
"""Click to colour different objects according to given Attribute Name"""
|
2021-01-23 14:17:50 +11:00
|
|
|
bl_idname = "bim.colour_by_attribute"
|
|
|
|
|
bl_label = "Colour by Attribute"
|
2021-07-06 12:19:45 +02:00
|
|
|
bl_options = {"REGISTER", "UNDO"}
|
2021-01-23 14:17:50 +11:00
|
|
|
|
|
|
|
|
def execute(self, context):
|
2021-07-07 10:25:19 +10:00
|
|
|
IfcStore.begin_transaction(self)
|
2021-07-29 23:08:17 +02:00
|
|
|
self.store_state(context)
|
2021-07-07 10:25:19 +10:00
|
|
|
result = self._execute(context)
|
|
|
|
|
IfcStore.add_transaction_operation(self)
|
|
|
|
|
IfcStore.end_transaction(self)
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
def _execute(self, context):
|
2021-01-23 14:17:50 +11:00
|
|
|
self.file = IfcStore.get_file()
|
|
|
|
|
colours = cycle(colour_list)
|
|
|
|
|
values = {}
|
|
|
|
|
attribute_name = context.scene.BIMSearchProperties.search_attribute_name
|
|
|
|
|
for obj in context.visible_objects:
|
|
|
|
|
if not obj.BIMObjectProperties.ifc_definition_id:
|
|
|
|
|
continue
|
|
|
|
|
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
2021-03-08 16:42:47 +11:00
|
|
|
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)
|
|
|
|
|
else:
|
|
|
|
|
value = getattr(element, attribute_name, None)
|
2021-01-23 14:17:50 +11:00
|
|
|
if value not in values:
|
|
|
|
|
values[value] = next(colours)
|
|
|
|
|
obj.color = values[value]
|
2021-07-29 23:08:17 +02:00
|
|
|
areas = [a for a in context.screen.areas if a.type == "VIEW_3D"]
|
2021-07-07 10:25:19 +10:00
|
|
|
if areas:
|
|
|
|
|
areas[0].spaces[0].shading.color_type = "OBJECT"
|
2021-01-23 14:17:50 +11:00
|
|
|
return {"FINISHED"}
|
|
|
|
|
|
2021-07-29 23:08:17 +02:00
|
|
|
def store_state(self, context):
|
|
|
|
|
areas = [a for a in context.screen.areas if a.type == "VIEW_3D"]
|
2021-07-07 10:25:19 +10:00
|
|
|
if areas:
|
|
|
|
|
self.transaction_data = {"area": areas[0], "color_type": areas[0].spaces[0].shading.color_type}
|
|
|
|
|
|
|
|
|
|
def rollback(self, data):
|
|
|
|
|
if data:
|
|
|
|
|
data["area"].spaces[0].shading.color_type = data["color_type"]
|
|
|
|
|
|
|
|
|
|
def commit(self, data):
|
|
|
|
|
if data:
|
|
|
|
|
data["area"].spaces[0].shading.color_type = "OBJECT"
|
|
|
|
|
|
2021-01-23 14:17:50 +11:00
|
|
|
|
|
|
|
|
class ColourByPset(bpy.types.Operator):
|
2021-08-01 17:33:55 +08:00
|
|
|
"""Click to colour different objects according to given Prop Name"""
|
2021-01-23 14:17:50 +11:00
|
|
|
bl_idname = "bim.colour_by_pset"
|
|
|
|
|
bl_label = "Colour by Pset"
|
2021-07-06 12:19:45 +02:00
|
|
|
bl_options = {"REGISTER", "UNDO"}
|
2021-01-23 14:17:50 +11:00
|
|
|
|
|
|
|
|
def execute(self, context):
|
2021-07-07 10:25:19 +10:00
|
|
|
IfcStore.begin_transaction(self)
|
2021-07-29 23:08:17 +02:00
|
|
|
self.store_state(context)
|
2021-07-07 10:25:19 +10:00
|
|
|
result = self._execute(context)
|
|
|
|
|
IfcStore.add_transaction_operation(self)
|
|
|
|
|
IfcStore.end_transaction(self)
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
def _execute(self, context):
|
2021-01-23 14:17:50 +11:00
|
|
|
self.file = IfcStore.get_file()
|
|
|
|
|
colours = cycle(colour_list)
|
|
|
|
|
values = {}
|
|
|
|
|
search_pset_name = context.scene.BIMSearchProperties.search_pset_name
|
|
|
|
|
search_prop_name = context.scene.BIMSearchProperties.search_prop_name
|
|
|
|
|
for obj in context.visible_objects:
|
|
|
|
|
if not obj.BIMObjectProperties.ifc_definition_id:
|
|
|
|
|
continue
|
|
|
|
|
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
|
|
|
|
psets = ifcopenshell.util.element.get_psets(element)
|
2021-06-06 20:55:25 +10:00
|
|
|
if search_pset_name == "":
|
|
|
|
|
props = {}
|
|
|
|
|
[props.update(p) for p in psets.values()]
|
|
|
|
|
else:
|
|
|
|
|
props = None
|
2021-03-08 16:42:47 +11:00
|
|
|
if context.scene.BIMSearchProperties.should_ignorecase:
|
2021-06-06 20:55:25 +10:00
|
|
|
props = props or next((v for k, v in psets.items() if k.lower() == search_pset_name.lower()), {})
|
2021-03-08 16:42:47 +11:00
|
|
|
value = str(next((v for k, v in props.items() if k.lower() == search_prop_name.lower()), None))
|
|
|
|
|
else:
|
2021-06-06 20:55:25 +10:00
|
|
|
props = props or psets.get(search_pset_name, {})
|
2021-03-08 16:42:47 +11:00
|
|
|
value = str(props.get(search_prop_name, None))
|
2021-01-23 14:17:50 +11:00
|
|
|
if value not in values:
|
|
|
|
|
values[value] = next(colours)
|
|
|
|
|
obj.color = values[value]
|
2021-07-29 23:08:17 +02:00
|
|
|
areas = [a for a in context.screen.areas if a.type == "VIEW_3D"]
|
2021-07-07 10:25:19 +10:00
|
|
|
if areas:
|
|
|
|
|
areas[0].spaces[0].shading.color_type = "OBJECT"
|
2021-01-23 14:17:50 +11:00
|
|
|
return {"FINISHED"}
|
|
|
|
|
|
2021-07-29 23:08:17 +02:00
|
|
|
def store_state(self, context):
|
|
|
|
|
areas = [a for a in context.screen.areas if a.type == "VIEW_3D"]
|
2021-07-07 10:25:19 +10:00
|
|
|
if areas:
|
|
|
|
|
self.transaction_data = {"area": areas[0], "color_type": areas[0].spaces[0].shading.color_type}
|
|
|
|
|
|
|
|
|
|
def rollback(self, data):
|
|
|
|
|
if data:
|
|
|
|
|
data["area"].spaces[0].shading.color_type = data["color_type"]
|
|
|
|
|
|
|
|
|
|
def commit(self, data):
|
|
|
|
|
if data:
|
|
|
|
|
data["area"].spaces[0].shading.color_type = "OBJECT"
|
|
|
|
|
|
2021-01-23 14:17:50 +11:00
|
|
|
|
|
|
|
|
class ColourByClass(bpy.types.Operator):
|
2021-08-01 17:33:55 +08:00
|
|
|
"""Click to colour different objects according to their IFC Classes"""
|
2021-01-23 14:17:50 +11:00
|
|
|
bl_idname = "bim.colour_by_class"
|
|
|
|
|
bl_label = "Colour by Class"
|
2021-07-06 12:19:45 +02:00
|
|
|
bl_options = {"REGISTER", "UNDO"}
|
2021-01-23 14:17:50 +11:00
|
|
|
|
|
|
|
|
def execute(self, context):
|
2021-07-07 10:25:19 +10:00
|
|
|
IfcStore.begin_transaction(self)
|
2021-07-29 23:08:17 +02:00
|
|
|
self.store_state(context)
|
2021-07-07 10:25:19 +10:00
|
|
|
result = self._execute(context)
|
|
|
|
|
IfcStore.add_transaction_operation(self)
|
|
|
|
|
IfcStore.end_transaction(self)
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
def _execute(self, context):
|
2021-01-23 14:17:50 +11:00
|
|
|
self.file = IfcStore.get_file()
|
|
|
|
|
colours = cycle(colour_list)
|
|
|
|
|
ifc_classes = {}
|
2021-07-29 23:08:17 +02:00
|
|
|
for obj in context.visible_objects:
|
2021-01-23 14:17:50 +11:00
|
|
|
if not obj.BIMObjectProperties.ifc_definition_id:
|
|
|
|
|
continue
|
|
|
|
|
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)
|
|
|
|
|
obj.color = ifc_classes[ifc_class]
|
2021-07-29 23:08:17 +02:00
|
|
|
areas = [a for a in context.screen.areas if a.type == "VIEW_3D"]
|
2021-07-07 10:25:19 +10:00
|
|
|
if areas:
|
|
|
|
|
areas[0].spaces[0].shading.color_type = "OBJECT"
|
2021-01-23 14:17:50 +11:00
|
|
|
return {"FINISHED"}
|
|
|
|
|
|
2021-07-29 23:08:17 +02:00
|
|
|
def store_state(self, context):
|
|
|
|
|
areas = [a for a in context.screen.areas if a.type == "VIEW_3D"]
|
2021-07-07 10:25:19 +10:00
|
|
|
if areas:
|
|
|
|
|
self.transaction_data = {"area": areas[0], "color_type": areas[0].spaces[0].shading.color_type}
|
|
|
|
|
|
|
|
|
|
def rollback(self, data):
|
|
|
|
|
if data:
|
|
|
|
|
data["area"].spaces[0].shading.color_type = data["color_type"]
|
|
|
|
|
|
|
|
|
|
def commit(self, data):
|
|
|
|
|
if data:
|
|
|
|
|
data["area"].spaces[0].shading.color_type = "OBJECT"
|
|
|
|
|
|
2021-01-23 14:17:50 +11:00
|
|
|
|
|
|
|
|
class ResetObjectColours(bpy.types.Operator):
|
2021-08-01 17:33:55 +08:00
|
|
|
"""Reset the colour of selected objects"""
|
2021-01-23 14:17:50 +11:00
|
|
|
bl_idname = "bim.reset_object_colours"
|
|
|
|
|
bl_label = "Reset Colours"
|
|
|
|
|
|
|
|
|
|
def execute(self, context):
|
2021-07-29 23:08:17 +02:00
|
|
|
for obj in context.selected_objects:
|
2021-01-23 14:17:50 +11:00
|
|
|
obj.color = (1, 1, 1, 1)
|
|
|
|
|
return {"FINISHED"}
|